2016-01-05 4 views
1

TLDR - что более идиоматично в NodeJS (ES2015) и почему?Идиоматическая инъекция зависимостей с NodeJS

Экспорт классов, экземпляр позже:

foo.js:

export default class Foo { 
} 

bar.js:

export default class Bar { 
    constructor(foo) { this.foo = foo; } 
} 

app.js:

import Foo from './foo'; 
import Bar from './bar'; 

new Bar(new Foo()); 

Экспорт экземпляры - эффективно сделать их одноэлементны:

foo.js:

class Foo { 
} 

export default new Foo(); 

bar.js:

import foo from './foo'; 

class Bar { 
} 

export default new Bar(); 

app.js:

import bar from './bar'; 

Я иду из мира Java. Внутри структуры DI обычно создают своего рода «контекст приложения» - они создают экземпляры классов и соединяют объекты вместе, помещая их в большой пакет, из которого вы можете получить все, что вам нужно.

Существует огромная разница между статическим «кодом импортом» (import com.acme.FooService, которая только импортирует определения класса) против получения экземпляра, который вы можете позвонить и т.д.

Что является наиболее распространенной , разумный способ сделать это в NodeJS? Опция «экземпляры экспорта» кажется мне грязной, похоже, что часть инфраструктуры, которая отвечает за загрузку , код также несет ответственность за , создавая объекты и проводя их вместе. Или, может быть, это ложная дихотомия, и на самом деле это путь к узлу?

+0

Лично я получаю много пробега из установки 'process.env.NODE_PATH' в мой каталог библиотек, поэтому я могу использовать' import' и по умолчанию это относиться к этому каталогу библиотек. Это похоже на инъекцию зависимостей, и до сих пор я не ощущал потребности в реальной инъекции зависимостей в моем программировании node.js. Но если вы хотите настроить зависимости между модулями в каком-то центральном месте, то это может мотивировать использование реальной контейнерной системы DI. –

+0

Еще один комментарий: в JS не нужны классы одноэлементов. Думайте объекты, а не классы. Вы можете просто создать объект, в котором вы должны написать одноэлементный класс на других языках. –

ответ

1

tl; dr: Нет причин, по которым вы не могли применять шаблоны инъекций зависимостей или классы экспорта в Node.js.

Основная причина, по которой вы сомневаетесь в том, чтобы экспортировать классы, даже если они имеют однолетнюю область действия в приложении, - это хакерский, динамичный характер JavaScript.

Конечно, вы действительно можете сделать довольно много, не прибегая к шаблону инъекции зависимостей.

Например, как вы упомянули, вы можете экспортировать экземпляры своих классов, тем самым делая их все однотонные. Модуль, экспортированный таким образом, даже не должен быть экземпляром любого класса.Рассмотрим следующие фрагменты кода:

export class Foo { 
    foo() { 
    } 

    bar() { 
    } 
} 

export default new Foo(); 

против:

export function foo() { 
} 

export function bar() { 
} 

Таким образом, это довольно распространенным способом в JavaScript экосистеме. Все в порядке, если нет внутреннего модуля состояние. Скажем, библиотека, открытый интерфейс которой состоит из множества функций (например, jquery, lodash и т. Д.). Но по-прежнему существует проблема, что некоторые классы (Bar в вашем примере) несут ответственность за выбор собственных зависимостей (Foo).

Вы также можете использовать некоторые хаки, такие как proxyquire. Это распространенный способ решения проблемы тестирования в JavaScript. С такими библиотеками вы можете перехватывать вызовы на require (не обязательно о поддержке синтаксиса модуля ES6, например, import) и предоставить свои собственные макеты/заглушки для целей тестирования.

Однако, поскольку приложение становится более сложным и увеличивается, DI может помочь в ремонтопригодности исходного кода.

Я думаю, что основная проблема применения методов DI в JS - это незрелость. Ни один из текущих решений DI в JavaScript действительно популярный на данный момент, поэтому не так много рекомендаций, нет учебников, нет инфраструктуры. Более того, многие библиотеки в JavaScript, заявляющие, что они являются контейнерами DI, либо загрязняют модули уродливыми аннотациями, либо фактически реализуют анти-шаблон или локализацию Service Locator.

Так что, я думаю, самый разумный способ заключается в следующем:

  1. Экспорт классов везде, где это возможно. Исключение: вы можете повторно экспортировать классы в виде сконструированных экземпляров в своем приложении Composition Root.
  2. Используйте Pure DI (без контейнера DI) в не очень сложных случаях или рассмотрите возможность использования некоторого контейнера DI (вам нужно сделать Google и сделать продуманный выбор).
  3. Избегайте переустройства. Не стесняйтесь, например, явно зависеть от некоторых внешних библиотек со стабильным API или ваших собственных модулей в слоях приложений или инфраструктуры (hovewer, я бы рекомендовал, чтобы ваш уровень домена/бизнес-логики оставался чистым).

Конечно, как и все, что связано с разработкой программного обеспечения, выбор между DI или экспортом синглетов зависит от сложности вашего программного обеспечения и ваших требований.