Внедрение в конструктор и когда использовать сервисный локатор - PullRequest
1 голос
/ 02 января 2011

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

1 Ответ

6 голосов
/ 02 января 2011

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

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

...