Как я могу вводить зависимости в зависимости от типа и имени с AngularDart?
У меня есть два сервиса, каждый из которых использует свой WebSocket в качестве параметра конструктора. Я хотел бы использовать внедрение зависимостей AngularDart для передачи соединения WebSocket, но я не могу полагаться только на типы (так как у меня есть две WebSockets).
Как я могу аннотировать или указать, какое конкретное соединение WebSocket должно быть с каждой службой?
Давайте представим, что у меня есть:
class ServiceOne {
WebSocket socketOne;
ServiceOne(this.socketOne);
}
а также
class ServiceTwo {
WebSocket socketTwo; // different connection
ServiceTwo(this.socketTwo);
}
Спасибо!
3 ответа
Эта проблема хорошо понимается, если вы посмотрите на GUICE. ( https://code.google.com/p/google-guice/). Проблема в том, что при извлечении экземпляра вам необходимо Key
(это то, что GUICE называет это). Есть несколько способов получить Key
,
В AngularJS мы упростили проблему и сказали, что имя параметра Key
, Поскольку у JS нет типов в исходном коде, это был действительно единственный выбор, который у нас был для Key
,
В AngualDart мы улучшили его и использовали Type
как Key
, Преимущество в том, что имя параметра не имеет значения. Но это создает проблему, что вы можете ввести только один из каждого Type
, Для пользовательских типов это не имеет большого значения, но иметь только один String
Тип конфигурации становится проблемой.
Решением этой проблемы является добавление аннотаций поверх типов. Чтобы Annotation
+ Type
это Key
, Вот как это может выглядеть:
ПРИМЕЧАНИЕ: ничего этого еще не существует, это всего лишь предложение, как это будет решено.
class MyClass {
MyClass(@Url String url, @Secret String secret) { ... }
}
Module module = new Module();
module.value(key(String, [Url]), 'http://server.com/...');
module.value(key(String, [Secret]), 'A89B42C');
ЗАПРОС: Поскольку ничего из этого еще не реализовано, если вы неравнодушны к помощи AngularDart и хотели бы помочь сделать это реальностью, пожалуйста, свяжитесь со мной.
Я не видел ничего о внедрении по именам типов. Это "большое" улучшение по сравнению с JS, что в Dart больше нет имен. Вы можете встраивать службы или сокеты в два разных класса, чтобы различать их.
Не видя некоторого кода, довольно сложно вносить предложения.
пример
library main;
import 'dart:html';
import 'package:angular/angular.dart';
import 'package:di/di.dart';
/**
* usage examples
*/
class ServiceOne {
WebSocketWrapper1 socketOne;
ServiceOne(this.socketOne);
void doSomething() {
socketOne.ws.xxx();
}
}
class ServiceTwo {
WebSocketWrapper2 socketTwo; // different connection
ServiceTwo(this.socketTwo);
void doSomething() {
socketTwo.ws.xxx();
}
}
}
@NgController(
selector: '[ng-controller=alert-demo-ctrl]',
publishAs: 'ctrl')
class AlertDemoController {
WebSocketOnDemandWrapper1 _wsodw1;
AlertDemoController(this._wsodw1) {
}
String sendData() {
_wsodw1.ws.send("somedata");
}
}
@NgController(
selector: '[ng-controller=accordion-demo-ctrl]',
publishAs: 'ctrl')
class AccordionDemoController {
WebSocketOnDemandWrapper2 _wsodw2;
AccordionDemoController(this._wsodw2) {
}
String sendData() {
_wsodw2.ws.send("somedata");
}
}
/**
* injectable WebSockets
*/
class WebSocketWrapper1 {
WebSocket ws;
WebSocketWrapper1(this.ws);
}
class WebSocketWrapper2 {
WebSocket ws;
WebSocketWrapper2(this.ws);
}
class WebSocketOnDemandWrapper1 {
WebSocket ws;
WebSocketOnDemandWrapper1(){
ws = new WebSocket('ws://127.0.0.1:1337/ws');
}
}
class WebSocketOnDemandWrapper2 {
WebSocket ws;
WebSocketOnDemandWrapper2(){
ws = new WebSocket('ws://127.0.0.1:3173/ws');
}
}
class MyAppModule extends Module {
MyAppModule() {
type(ServiceOne);
type(ServiceTwo);
type(AlertDemoController);
type(AccordionDemoController);
type(WebSocketOnDemandWrapper1); // connect on demand
type(WebSocketOnDemandWrapper2); // connect on demand
// start connection on app startup and provide this connection when requested
value(WebSocketWrapper1, new WebSocketWrapper1(new WebSocket('ws://127.0.0.1:1337/ws')));
value(WebSocketWrapper2, new WebSocketWrapper2(new WebSocket('ws://127.0.0.1:3173/ws')));
}
}
void main() {
ngBootstrap(module: new MyAppModule());
}
DI 0.0.34 получил специальную поддержку для этого варианта использования с использованием аннотаций
Аннотация с параметрами не поддерживается. Я не уверен, что это все еще запланировано ( https://github.com/angular/di.dart/issues/46)
Я также добавил пример того, как примитивы теперь можно использовать с DI. (не уверен, что это еще полезно)
import 'package:di/di.dart';
import 'package:di/dynamic_injector.dart';
/**
* Annotation used to mark classes for which static type factory must be
* generated. For testing purposes not all classes are marked with this
* annotation, some classes are included in @Injectables at the top.
*/
class Injectable {
const Injectable();
}
/**
* Some dummy WebSocket class (just for demonstration)
*/
@Injectable()
class WebSocket {
String url;
WebSocket(this.url);
}
/**
* Allows to mark an injectable as 'one'
*/
class One {
const One();
}
/**
* Allows to mark an injectable as 'two'
*/
class Two {
const Two();
}
/**
* A class that implements updates.
* It needs a websocket marked as 'one'
*/
class Updates {
WebSocket ws;
Updates(@One() this.ws);
}
/**
* A class that implements chats.
* It needs a websocket marked as 'two'
*/
class Chat {
WebSocket ws;
Chat(@Two() this.ws);
}
/**
* The application module
*/
class AppModule extends Module {
AppModule() {
value(String, 'http://www.google.com', withAnnotation: AjaxUrl);
value(int, 8080, withAnnotation: ServerPort);
value(int, 1000);
factory(WebSocket, (Injector i) => new WebSocket('ws://game.example.com:12010/updates'), withAnnotation: One);
factory(WebSocket, (Injector i) => new WebSocket('ws://chat.example.com/games'), withAnnotation: Two);
type(Chat);
type(Updates);
}
Injector _injector;
Injector get injector {
if (_injector == null) {
_injector = new DynamicInjector(modules: [this]);
// Static injector => comment in and comment out above
// _injector = new StaticInjector(modules: [this],
// typeFactories: type_factories_gen.typeFactories);
}
return _injector;
}
}
/**
* Allows to mark a String as ajax url
* Just to demonstrate how to use primitive types with DI
*/
class AjaxUrl {
const AjaxUrl();
}
/**
* Allows to mark an int as server port
* Just to demonstrate how to use primitive types with DI
*/
class ServerPort {
const ServerPort();
}
void main(List<String> args) {
var module = new AppModule();
print('AjaxUrl: ${module.injector.get(String, AjaxUrl)}');
print('ServerPort: ${module.injector.get(int, ServerPort)}');
// primitives without annotation are not supported and throw an exception
// print('int: ${module.injector.get(int)}');
print('Chat: ${module.injector.get(Chat).ws.url}');
print('Updates: ${module.injector.get(Updates).ws.url}');
}