Сибирские интеграционные системы
AngularSIS #1.18 - https://www.youtube.com/playlist?list=PLmEQRj1_Mt5fkeBYOw1o8k_o8-7POFZJN JavaSIS #2.19 - https://www.youtube.com/playlist?list=PLmEQRj1_Mt5f5MlXGlf5kzldb9Rl8Pwuo
План занятия
1) Паттерн Dependency Injection(DI)
2) Реализация DI внутри Angular
3) Сервисы
4) Практика
Пример самостоятельного создания зависимостей
class Car {
public engine: IEngine;
public tires: ITires;
constructor() {
this.engine = new Engine(EngineTypes.HORSE);
this.tires = new Tires(TireTypes.WOOD_WHEEL);
}
}
Интерфейсы
this.myCar = new Car();
Создаем машину (снаружи)
После компиляции...
Спустя некоторое время
class SimpleCar {
public engine: IEngine;
public tires: ITires;
constructor() {
this.engine = new Engine(EngineTypes.HORSE);
this.tires = new Tires(TireTypes.WOOD_WHEEL);
}
}
class FantasyCar {
public engine: IEngine;
public tires: ITires;
constructor() {
this.engine = new Engine(EngineTypes.DRAGON);
this.tires = new Tires(TireTypes.MAGIC_WHEEL);
}
}
this.car1 = new SimpleCar();
this.car2 = new FantasyCar();
Создание экземпляров:
Спустя еще некоторое время
Появляется новый тип двигателя
Нужно вручную обновить каждый класс
class SimpleCar {
public engine: IEngine;
public tires: ITires;
constructor() {
this.engine = new Engine(EngineTypes.HORSE);
this.tires = new Tires(TireTypes.WOOD_WHEEL);
}
}
class FantasyCar {
public engine: IEngine;
public tires: ITires;
constructor() {
this.engine = new Engine(EngineTypes.DRAGON);
this.tires = new Tires(TireTypes.MAGIC_WHEEL);
}
}
class CarWith2Horses {
public engine: IEngine;
public tires: ITires;
constructor() {
this.engine = new Engine(EngineTypes.DOUBLE_HORSE);
this.tires = new Tires(TireTypes.WOODEN_WHEEL);
}
}
class WinterCar {
public engine: IEngine;
public tires: ITires;
constructor() {
this.engine = new Engine(EngineTypes.POLAR_BEAR);
this.tires = new Tires(TireTypes.SNOW_RUNNER);
}
}
Итого
1. Получаем много ручной работы (долго)
2. Много изменений в коде (потенциальные баги)
3. Код обладает сильным зацеплением
(сложнее поддерживать)
Зацепление vs Связность
Полезные ссылки по связности и зацеплению
1) Связность кода
https://ru.wikipedia.org/wiki/Связность_(программирование)
2) Зацепление
https://ru.wikipedia.org/wiki/Зацепление_(программирование)
Как быть?
Поможет Dependency Injection!
Dependency Injection
Шутка :) Этого слайда не будет
Dependency Injection
Ключевые моменты паттерна Dependency Injection
1) Зависимостями ( dependencies) являются сервисы или объекты, которые требуются классу для работы
2) Суть подхода в получении зависимостей извне, вместо того, чтобы создавать экземпляры зависимостей самому
Пример без Dependency Injection
class Car {
public engine: IEngine;
public tires: ITires;
constructor() {
this.engine = new Engine(EngineTypes.HORSE);
this.tires = new Tires(TireTypes.WOOD_WHEEL);
}
}
this.myCar = new Car();
Пример с использованием Dependency Injection
class Car {
constructor(
public engine: IEngine,
public tires: ITires) {
}
}
this.myCar = new Car(
new Engine(EngineTypes.HORSE),
new Tires(TireTypes.WOOD_WHEEL));
Пример с использованием Dependency Injection
this.myCar = new Car(
new Engine(EngineTypes.HORSE),
new Tires(TireTypes.WOOD_WHEEL));
class Car {
constructor(
public engine: IEngine,
public tires: ITires) {
}
}
class Car {
public engine: IEngine;
public tires: ITires;
constructor(engine: IEngine, tires: ITires) {
this.engine = engine;
this.tires = tires;
}
}
Спустя некоторое время
class Car {
constructor(
public engine: IEngine,
public tires: ITires) {
}
}
class FantasyCar {
public engine: IEngine;
public tires: ITires;
constructor() {
this.engine = new Engine(EngineTypes.DRAGON);
this.tires = new Tires(TireTypes.MAGIC_WHEEL);
}
}
this.car1 = new Car(
new Engine(EngineTypes.HORSE),
new Tires(TireTypes.WOOD_WHEEL));
this.car2 = new Car(
new Engine(EngineTypes.DRAGON),
new Tires(TireTypes.MAGIC_WHEEL));
Создание экземпляров
Класс
После компиляции...
Итого
1. Изменяем реализацию зависимости, нет необходимости менять сам класс (класс ожидает что-то, удовлетворяющее интерфейсу)
2. Изменения происходят в точке создания класса (затрагивают меньшую область)
3. Код стал менее зацепленным за счет использования внешних зависимостей (легче заменять отдельные компоненты системы)
Реализация DI внутри Angular
!Важно!
В сервисах должна находиться вся логика приложения, не связанная с отображением данных в компоненте
Не держать в сервисах данные о состоянии (стейты), это плохая практика
Пример DI внутри Angular
import { Injectable } from '@angular/core';
@Injectable()
export class SimpleService {
getSomeData() { return SOME_DATA; }
}
import { Component } from '@angular/core';
import { SimpleService } from './simple.service';
@Component({
selector: 'app-some-data',
template: `<p>{{someData}}</p>`,
providers: [SimpleService]
})
export class SomeDataComponent implements OnInit {
someData: string;
constructor(private someServiceName: SimpleService) {
}
ngOnInit() {
this.someData = this.someServiceName.getSomeData();
}
}
Сервис
Компонент
* Потенциально тяжелые действия выполняем в ngOnInit вместо конструктора
@Component({
selector: 'app-some-data',
template: `
<p>{{someData}}</p>
`,
providers: [SimpleService]
})
export class SomeDataComponent {
...
}
Способы указать сервис для DI
Способ №1. В компоненте или модуле
@NgModule({
imports: [ BrowserModule ],
providers: [ SimpleService ],
declarations: [ AppComponent ],
exports: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
import { Injectable } from '@angular/core';
import { SOME_DATA } from './mock-data';
@Injectable({
providedIn: 'root',
})
export class SimpleService {
getData() { return SOME_DATA; }
}
* Новая фича ангуляра. У нас пока не используется (отлично подходит для библиотек, но хуже для приложений)
Способы указать сервис для DI
Способ №2. В сервисе
Dependency Injector
Экземпляр сервиса
Иерархическая инъекция зависимостей
Практика
- Переносим работу с задачами в канбане - в сервис
- Работаем с рест-сервером на Java
Запуск jar-файла с сервером:
C:\git\my-angular-project\src\resources> java -jar <название файла>
Проверяем что установлена java
C:\git\my-angular-project\src\resources> java -version
Если не установлена, то скачиваем 8 версию (JRE)
http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html
Посмотреть содержимое базы данных
1. Перейти по адресу localhost:8080/h2
2. Проверить что в пункте JDBC URL указано значение:
jdbc:h2:~/kanban
3. Нажать на кнопку Connect
Посмотреть содержимое базы данных
4. В появившемся окне можно вводить SQL-запросы
1
2
3
Полезные ссылки
1) Статья о паттерне DI
https://habr.com/post/350068/
2) Документация Angular. Блок статей по DI
https://angular.io/guide/dependency-injection
3) Документация RxJS. Описание Subject
http://reactivex.io/rxjs/manual/overview.html#subject
Домашнее задание №7
1. Перенести логику работы с задачами (а также стадиями и досками) в канбане из компонентов в сервис (или несколько сервисов):
- создание/редактирование/удаление задачи
- создание/редактирование/удаление стадии
Опционально (по желанию):
- создание/редактирование/удаление доски
- отображение нескольких досок
2. Реализовать работу с рест-сервером из примера на лекции
* Не забыть прислать ссылку на pull-request на почту
checkhomework.sis@gmail.com
Спасибо за внимание!
By Сибирские интеграционные системы
Сервисы и Dependency Injection