Я изо всех сил пытаюсь понять части использования 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.