2016-10-24 5 views
0

Я прочитал кучу вопросов и всех документов в вики Ninject, но я все еще сомневаюсь и задаю себе вопросы: «Я делаю это правильно?»Правильный способ использования инъекции зависимостей, когда некоторые аргументы будут известны только во время выполнения

  1. Что делать, если мне нужно использовать контроллер для инициализации объекта? И Поле аргумент будет известен только по адресу runtime?

A) Так что мне нужно что-то вроде этого:

public class MyClass : IMyInterface 
    { 
     private string _field; 
     readonly IRepository _repo; 
     public MyClass(string field, IRepository repo) 
     { 
      _field = field; 
      _repo = repo; 
     } 
    } 

Но как связать это правильно? Или я должен навсегда забыть об использовании конструктора по какой-либо причине, кроме интродукции зависимостей конструктора?

B) и сделать это нравится:

public class MyClass : IMyInterface 
{ 
    private string _field; 
    readonly IRepository _repo; 
    public MyClass(IRepository repo) 
    { 
     _repo = repo; 
    } 
    public void Initialize(string field) 
    { 
     _field = field; 
    } 
} 

Я думаю, что это не нормально, чтобы позвонить в любое время, когда мне нужно приемлю эту функцию Initialize, или я ошибаюсь?

В соответствии с этим ответы Can't combine Factory/DI и Dependency Inject (DI) "friendly" library и Is there a pattern for initializing objects created via a DI container

Использование Abstract Factory, если вам нужно недолгим объект

зависимостями инъецированные Конструктора инъекций, как правило, долговечны, но иногда вам нужно короткоживущий объект, или построить зависимость, основанную на значении, известном только во время выполнения.

C) я должен делать это нравится:

public interface IMyInterface { } 
    public interface IMyFactory 
    { 
     MyClass Create(string field); 
    } 
    public class MyFactory : IMyFactory 
    { 
     private readonly IRepository _repo; 
     public MyFactory (IRepository repo) 
     { 
      _repo = repo; 
     } 
     public MyClass Create(string field) 
     { 
      return new MyClass(_repo, field); 
     } 
    } 
    public class MyClass : IMyInterface 
    { 
     private string _field; 
     readonly IRepository _repo; 
     public MyClass(IRepository repo, string field) 
     { 
      _repo = repo; 
      _field = field; 
     } 
    } 

И если мне нужно MyClass из другого класса я собираюсь использовать его как

public class OtherClass 
{ 
    private IMyInterface _myClass; 
    public OtherClass(IMyFactory factory) 
    { 
     _myClass = factory.Create("Something"); 
    } 
} 

Не слишком громоздким ?

И мой вопрос: что мне нужно использовать в случае A, B или C? И почему? Или может быть что-то еще?

+0

Пожалуйста, отредактируйте свой вопрос на несколько сфокусированных, потому что он в настоящее время слишком широк, и он, вероятно, будет закрыт в текущей форме, хотя он хороший ... – kayess

+0

@kayess done. Я отрезал половину вопроса. Спасибо за совет – PilgrimViis

+0

@PilgrimViis по-прежнему не подходит для SO, к сожалению, может быть, идея прочитать FAQ и, возможно, опубликовать их на одном из других сайтов. – ChrisBint

ответ

2

Что делать, если мне нужно использовать контроллер для инициализации объекта? И аргумент поля будет известен только во время выполнения?

Как объяснено, here, ваши компоненты приложения не должны запрашивать данные во время инициализации. Вместо этого вы должны либо:

  1. передачи во время выполнения данных через вызовы методов в API или
  2. получить во время выполнения данных из конкретных абстракций, которые позволяют разрешению данных во время выполнения.

Вопреки распространенному мнению, абстрактные заводы вряд ли когда-нибудь правильное решение этой проблемы, потому что:

Вместо снижения сложности для потребителя, завод фактически увеличивает сложность, потому что вместо того, чтобы просто зависимость от сервисов абстракции IService, потребитель теперь требует зависимости как от IService, так и от Abstract Factory IServiceFactory. [...] увеличение сложности можно почувствовать мгновенно при модульном тестировании таких классов. Это не только заставляет нас проверять взаимодействие, которое имеет потребитель с услугой, мы должны также проверить взаимодействие с заводом.

Подробнее см. this article.

1

Ответ, как всегда, зависит. Без контекста будет сложно советовать.

Однако есть одна вещь, которую я бы смутил - настроить для ввода «чистой» строки в компоненты. Строка может означать тысячи вещей, и может быть очень сложно поддержать этот дизайн позже. Конечно, вы можете определить, что строка, введенная в XController, будет строкой соединения с SQL, а при вводе в YController будет токен авторизации, но я сомневаюсь, что он будет читабельным и простым в обслуживании.

Это было сказано, я бы выбрал вариант C или после подхода:

public class DescriptiveMeaningOfAClass 
    { 
     public string Value { get; set; } 
    } 

    public class MyClass : IMyInterface 
    { 
     private string _field; 
     readonly IRepository _repo; 
     public MyClass(DescriptiveMeaningOfAClass something, IRepository repo) 
     { 
      _field = something.Value; 
      _repo = repo; 
     } 
    } 
0

Personnaly Я бы смешивать А) и С), используя ChildKernel вместо ссылки непосредственно конструктор. https://github.com/ninject/Ninject.Extensions.ChildKernel

В вашем заводе:

var parentKernel = new StandardKernel(); 

var childKernel1 = new ChildKernel(parentKernel); 
childKernel1.Bind<string>().ToConstant("MyRuntimeValue"); 
var myClass = childKernel1.Get<MyClass>(); 

Я не проверял, но он должен работать.