1

Я пытаюсь понять части использования StructureMap. В частности, в документации заявление делается в отношении общего антишаблона использования StructureMap в качестве локатора службы только вместо инъекции конструктора (образцы коды прямо из StructureMap документации):Инъекция конструктора и когда использовать локатор обслуживания

public ShippingScreenPresenter() 
    { 
     _service = ObjectFactory.GetInstance<IShippingService>(); 
     _repository = ObjectFactory.GetInstance<IRepository>(); 
    } 

вместо:

public ShippingScreenPresenter(IShippingService service, IRepository repository) 
    { 
     _service = service; 
     _repository = repository; 
    } 

Это прекрасно в течение очень короткого графа объектов, но при работе с объектами много уровней глубокими, означает ли это, что вы должны пройти вниз всю зависимость, необходимую для более глубоких объектов прямо с вершины? Разумеется, это нарушает инкапсуляцию и предоставляет слишком много информации о реализации более глубоких объектов.

Предположим, что я использую шаблон Active Record, поэтому моей записи нужен доступ к хранилищу данных, чтобы иметь возможность сохранять и загружать себя. Если эта запись загружается внутри объекта, вызывает ли объект ObjectFactory.CreateInstance() и передает его в конструктор активной записи? Что делать, если этот объект находится внутри другого объекта. Требуется ли IRepository в качестве собственного параметра дальше? Это предоставит родительскому объекту тот факт, что в данный момент мы получаем доступ к хранилищу данных, что, вероятно, не должен знать внешний объект.

public class OuterClass 
{ 
    public OuterClass(IRepository repository) 
    { 
     // Why should I know that ThingThatNeedsRecord needs a repository? 
     // that smells like exposed implementation to me, especially since 
     // ThingThatNeedsRecord doesn't use the repo itself, but passes it 
     // to the record. 
     // Also where do I create repository? Have to instantiate it somewhere 
     // up the chain of objects 
     ThingThatNeedsRecord thing = new ThingThatNeedsRecord(repository); 
     thing.GetAnswer("question"); 
    } 
} 

public class ThingThatNeedsRecord 
{ 
    public ThingThatNeedsRecord(IRepository repository) 
    { 
     this.repository = repository; 
    } 

    public string GetAnswer(string someParam) 
    { 
     // create activeRecord(s) and process, returning some result 
     // part of which contains: 
     ActiveRecord record = new ActiveRecord(repository, key); 
    } 

    private IRepository repository; 
} 

public class ActiveRecord 
{ 
    public ActiveRecord(IRepository repository) 
    { 
     this.repository = repository; 
    } 

    public ActiveRecord(IRepository repository, int primaryKey); 
    { 
     this.repositry = repository; 
     Load(primaryKey); 
    } 

    public void Save(); 

    private void Load(int primaryKey) 
    { 
     this.primaryKey = primaryKey; 
     // access the database via the repository and set someData 
    } 

    private IRepository repository; 
    private int primaryKey; 
    private string someData; 
} 

Любые мысли будут оценены.

Саймон

РЕДАКТИРОВАТЬ: мнение, кажется, что инъекция должна начинаться в верхнем слое. ActiveRecord будет введен в ThingThatNeedsRecord, который вводится в OuterClass. Проблема с этим заключается в том, что если ActiveRecord необходимо создать с помощью параметра времени выполнения (например, идентификатор записи для извлечения). Если я вставляю ActiveRecord в ThingThatNeedsRecord прямо вверху, мне как-то нужно выяснить, какой идентификатор должен быть в этот момент (который предоставляет верхний уровень реализации, которого он не должен), или мне нужно иметь частично сконструированный ActiveRecord и установите Идентификатор позже. Это становится более сложным, если мне нужно N записей и не будет знать до выполнения логики внутри ThingThatNeedsRecord.

+0

Возможный дубликат: http://stackoverflow.com/questions/4570750/dependency-injection-turtles-all-the-way-down –

+0

Связанный: http://stackoverflow.com/questions/2420193/dependency-injection- Конструктор-безумие/2420245 # 2420245 –

ответ

6

Инверсия контроля - это как насилие. Если это не решит вашу проблему, вы не используете ее достаточно. Или something like that.

Более того, я думаю, что ваш OuterClass должен иметь ThingThatNeedsRecord, введенный в него с помощью инъектора конструктора. Аналогично ThingThatNeedsRecord должен иметь в своем распоряжении ActiveRecord. Это не только решит вашу непосредственную проблему, но и сделает ваш код более модульным и проверенным.

+0

Я думаю, что это связано с моей первоначальной заботой. Если я создаю ThingThatNeedsRecord над OuterClass и вставляя в него ActiveRecord, тогда объект выше OuterClass подвергается внутренним реализациям ThingThatNeedsRecord вниз в графе объектов. – Simon

+0

Если вы создаете 'OuterClass' через контейнер (StructureMap), тогда код, который потребляет' OuterClass', не подвергается зависимости от ThingThatNeedsRecord'. Правильно настроенный контейнер предоставит 'ThingThatNeedsRecord'' OuterClass', а также рекурсивную обработку любых других зависимостей в графе объектов. –

+1

В конечном итоге на верхнем уровне у вас будет вызов службы, где вы получаете объект из ObjectFactory. Тем не менее, все зависимости этого объекта (и их зависимости) будут удовлетворены контейнером, поэтому код, который вызывает вызов местоположения службы, не обязательно должен знать об этих зависимостях. –