KEMBAR78
"Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15 | PDF
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
Result 
Locator.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
Result 
Locator.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.js 
gobwas@gmail.com

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

  • 1.
    Dependency Injection. Javascript. Сергей Камардин
  • 2.
    Задача из жизни 1. Разместить на карте зарегистрированных пользователей; ! 2
  • 3.
    «JS Way» Locator.prototype.locateUsers= function(users) { // Инициалиация сервиса карт loadScript("..."); client.init(...); ! // Создание карты var map = new client.Map(...); ! // Отображение на карте маркеров users.forEach(...); } 3
  • 4.
    Задача из жизни 1. Разместить на карте зарегистрированных пользователей; 2. Поменять поставщика карт; 4
  • 5.
    Решение: Абстракция AbstractMapService.prototype= { ! createMap: function() { throw new TypeError("Not implemented"); }, ! createMapMarker: function() { throw new TypeError("Not implemented"); } ! } 5
  • 6.
    Имплементация AbstractMapService.extend({ ! createMap: function(id, options) { // }, ! createMapMarker: function(map, options) { // } ! }); 6
  • 7.
    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
  • 8.
    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
  • 9.
    Проблемы • Невозможнонаписать юнит тесты; • Использование сервиса карт во многих местах в коде; • Избыточная функциональность локатора; • Reusability. 9
  • 10.
    Задача из жизни 1. Разместить на карте зарегистрированных пользователей; 2. Поменять поставщика карт; 3. Перенести локатор в другой проект, как плагин. 10
  • 11.
    Result Locator.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.
  • 13.
    Result Locator.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 Вот оно
  • 14.
    Routine // CreateMapService var mapService = new MapService(...); ! // Create Locator var locator = new Locator(); ! // Inject mapService locator.setMapService(mapService); ! // Use locator locator.locateUsers(users); 14
  • 15.
    Inversion of Control • Dependency Injection • Service Locator • Factory Method IoC container: 15
  • 16.
    Dependency Injection •Constructor injection • Setter injection • Interface injection 16
  • 17.
  • 18.
  • 19.
  • 20.
    Плюсы • Каждыйобъект отвечает за свою функцию; • Соблюден принцип инверсии зависимостей; • Простая конфигурация объектов; • Безболезненная смена имплементаций; • Легко писать юнит тесты. 20
  • 21.
    dm.js • JavascriptРеализация IoC; • Работает в node.js и браузере; • Легко расширяется (любые загрузчики скриптов и Promise/A+ библиотеки); • Простая конфигурация (в духе Symfony). 21
  • 22.
    Конфигурация "locator": { path: "path/to/locator/implementation", calls: [ ["setMapService", ["@maps"]] ] } "maps": { path: "path/to/map/service/implementation", arguments: [{ id: "my-app-id" }] } 22
  • 23.
    Использование dm .get("locator") .then(function(locator) { locator.locateUsers(users); }); 23
  • 24.
    Тестирование it("should createmap", function() { var mapStub, locator; ! mapMock = sinon .mock(new AbstractMapService) .expects("createMap") .once(); ! locator = new Locator(); locator.setMapService(mapMock); ! locator.locateUsers(...); ! mapMock.verify(); }); 24
  • 25.
    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
  • 26.
    Альтернативы • Wire.js • Angular’s DI • Тупо контейнеры 26
  • 27.
    Где и длячего это можно использовать? 27
  • 28.
    Спасибо! Сергей Камардин github.com/gobwas/dm.js gobwas@gmail.com