"dependency injection. javascript.", Сергей Камардин, moscowjs 15

Post on 09-Jun-2015

846 Views

Category:

Software

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

Слайды доклада "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15

TRANSCRIPT

Dependency Injection. Javascript.

Сергей Камардин

Задача из жизни

1. Разместить на карте зарегистрированных пользователей;

!

2

«JS Way»Locator.prototype.locateUsers = function(users) { // Инициалиация сервиса карт loadScript("..."); client.init(...); ! // Создание карты var map = new client.Map(...); ! // Отображение на карте маркеров users.forEach(...); }

3

Задача из жизни

1. Разместить на карте зарегистрированных пользователей;

2. Поменять поставщика карт;

4

Решение: АбстракцияAbstractMapService.prototype = { ! createMap: function() { throw new TypeError("Not implemented"); }, ! createMapMarker: function() { throw new TypeError("Not implemented"); } !}

5

ИмплементацияAbstractMapService.extend({ ! createMap: function(id, options) { // }, ! createMapMarker: function(map, options) { // } !});

6

Locator.prototype.locateUsers = function(users) { // Create map service // Could be an Fabric Method, Service Locator, DI var mapService = new ConcreteMapService(...); ! // Create map var map = mapService.createMap(...); ! // Run each users, making markers users.forEach(...); }

7

Single responsibility?Locator.prototype.locateUsers = function(users) { // Create map service // Could be an Fabric Method, Service Locator, DI var mapService = new ConcreteMapService(...); ! // Create map var map = mapService.createMap(...); ! // Run each users, making markers users.forEach(...); }

8

Проблемы

• Невозможно написать юнит тесты;

• Использование сервиса карт во многих местах в коде;

• Избыточная функциональность локатора;

• Reusability.

9

Задача из жизни

1. Разместить на карте зарегистрированных пользователей;

2. Поменять поставщика карт;

3. Перенести локатор в другой проект, как плагин.

10

ResultLocator.prototype = { // injection setMapService: function(mapService) { this.mapService = mapService; }, ! locateUsers: function(users) { // Create map var map = this.mapService.createMap(...); ! // Run each users, making markers users.forEach(...); } }

11

12

ResultLocator.prototype = { // injection setMapService: function(mapService) { this.mapService = mapService; }, ! locateUsers: function(users) { // Create map var map = this.mapService.createMap(...); ! // Run each users, making markers users.forEach(...); } }

13

Вот оно

Routine// Create MapService var mapService = new MapService(...); !// Create Locator var locator = new Locator(); !// Inject mapService locator.setMapService(mapService); !// Use locator locator.locateUsers(users);

14

Inversion of Control

• Dependency Injection

• Service Locator

• Factory Method

IoC container:

15

Dependency Injection

• Constructor injection

• Setter injection

• Interface injection

16

Hard Coupling

17

Coupling

18

Loose Coupling

19

Плюсы• Каждый объект отвечает за свою функцию;

• Соблюден принцип инверсии зависимостей;

• Простая конфигурация объектов;

• Безболезненная смена имплементаций;

• Легко писать юнит тесты.

20

dm.js

• Javascript Реализация IoC;

• Работает в node.js и браузере;

• Легко расширяется (любые загрузчики скриптов и Promise/A+ библиотеки);

• Простая конфигурация (в духе Symfony).

21

Конфигурация "locator": { path: "path/to/locator/implementation", calls: [ ["setMapService", ["@maps"]] ] } "maps": { path: "path/to/map/service/implementation", arguments: [{ id: "my-app-id" }] }

22

Использование

dm .get("locator") .then(function(locator) { locator.locateUsers(users); });

23

Тестированиеit("should create map", function() { var mapStub, locator; ! mapMock = sinon .mock(new AbstractMapService) .expects("createMap") .once(); ! locator = new Locator(); locator.setMapService(mapMock); ! locator.locateUsers(...); ! mapMock.verify(); });

24

Syntax! "example": { "path": "...", "arguments": [{ "service": "@service", "method": "@service:method" "result": "@service:method[1,2,3]", "resource": "#path/to/my.tpl#", "path": "http://%{api_path}" "build": "build_no_#{file.txt}" }] } !

25

Альтернативы

• Wire.js

• Angular’s DI

• Тупо контейнеры

26

Где и для чего это можно использовать?

27

Спасибо!

github.com/gobwas/dm.jsgobwas@gmail.com

Сергей Камардин

top related