Мы хотим полагаться на интерфейсы вместо конкретных в наших объектно-ориентированных решениях, однако, когда вы внедряете сервис в компонент Angular, вы обычно используете конкретный, поскольку после компиляции приложение представляет собой просто javascript, а в javascript нет интерфейсов.
Я только что видел код, который решает эту проблему следующим образом:
export const serviceProvider = new InjectionToken<CustomTypeCreatedUsingGenericsForComposition>('CustomTypeCreatedUsingGenericsForComposition');
а затем в поставщиках модулей:
{
provide: CustomTypeCreatedUsingGenericsForComposition,
useClass: AnInstance,
}
а затем в компоненте:
constructor(
@Inject(ResidentialKeysListBLLProvider)
private residentialKeysListBLL: ResidentialKeysListBLL
) {}
Реализация теперь отделена от DI, и для изменения службы вы меняете useClass. Токен, по сути, действует как оболочка для возможности прямого использования интерфейса в качестве аргумента DI.
Это кажется замечательным, так как мы в основном достигли принципа инверсии зависимостей в SOLID, но мы добавили сложности для чего-то, что в любом случае должно быть очень специфичным, поскольку оно предоставляется на уровне модуля. Так действительно помогает?
Вы можете использовать InjectionToken, но, на мой взгляд, есть гораздо лучшее решение.
В Angular DI нельзя инжектить интерфейсы, но вы можете вводить абстрактные классы.
Простой интерфейс:
export interface IVehicleService {
doSomething(param1: string; param2: string);
}
Простой абстрактный класс:
export abstract class VehicleService implements IVehicleService {
abstract doSomething(param1: string; param2: string);
}
Класс бетона:
@Injectable()
export class MazdaVehicleService extends VehicleService {
doSomething(param1: string; param2: string) {...}
}
Правило DI:
@NgModule({
providers: [
{ provide: VehicleService, useClass: MazdaVehicleService }
]
})
На мой взгляд, вы добавляете дополнительную сложность ради ощущения теплоты и нечеткости SOLID. Помните, что Typescript — это не C# или Java, даже если он «по ощущениям» похож на него. Когда вы объявляете провайдеров в модуле, вы уже можете легко поменять их местами без создания всех этих токенов.