Как я могу вводить зависимости в зависимости от типа и имени с 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}');
}
Другие вопросы по тегам