Внедрение зависимостей - требуется новый экземпляр в нескольких методах классов - PullRequest
28 голосов
/ 10 января 2011

У меня есть код, который выглядит примерно так:

public MyService(IDependency dependency)
{
    _dependency = dependency;
}

public Message Method1()
{
    _dependency.DoSomething();

}

public Message Method2()
{
    _dependency.DoSomething();  
}

public Message Method2()
{
    _dependency.DoSomething();  
}

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

Так каков наилучший способ сделать это и при этом не обновлять конкретный экземпляр?

Вы бы использовали контейнер IoC и сделали бы вызов контейнера в каждом из методов? Или есть более простой способ, когда вы можете сделать только один вызов контейнера?

Что если бы я не использовал контейнер IoC - был бы способ не обновлять конкретный экземпляр в каждом методе?

Ответы [ 5 ]

37 голосов
/ 10 января 2011

Большинство ответов здесь пока предлагают изменить тип введенной зависимости на Абстрактная фабрика (Func<T> также является Абстрактной фабрикой) для решения этой проблемы.Однако, если вы сделаете это, это будет негерметичная абстракция , потому что вы позволите знанию конкретной реализации определять дизайн потребителя.Это нарушает принцип подстановки Лискова .

Лучшим вариантом будет сохранить MyService таким, как он есть , а затем создать оболочку для IDependency, которая решает конкретную проблему времени жизни:

public class TransientDependencyWrapper : IDependency
{
    public void DoSomething()
    {
        new MyStatefulDependency().DoSomething();
    }
}

Внедрить это в MyService вместо прямой инъекции в исходную реализацию (MyStatefulDependency).

Если вы хотите абстрагироваться от создания зависимости, вы всегда можете внедрить Abstract Factory вэтот уровень.

9 голосов
/ 10 января 2011

Похоже, вы должны ввести поставщика / фабрики. Как вы представляете, это зависит от вас (и что поддерживает ваш IoC) - это может быть так просто, как:

public MyService(Func<IDependency> dependencyProvider)
{
    this.dependencyProvider = dependencyProvider;
}

public Message Method1()
{
    IDependency dependency = dependencyProvider();
    dependency.DoSomething();    
}

... или у вас может быть интерфейс для этого определенного фабричного типа, или универсальный IFactory<T> и т. Д. Существуют всевозможные возможности - но основной момент в том, что вы вводите то, что вам нужно , что в данном случае является «способом создания новой реализации IDependency для каждого вызова».

5 голосов
/ 10 января 2011

Если вам нужно создать несколько экземпляров внедренного типа, вы должны вместо этого ввести IDependencyFactory, который будет отвечать за управление жизненными циклами экземпляров:

interface IDependencyFactory
{
    IDependency GetInstance();
}
3 голосов
/ 10 января 2011

Вы можете сделать это так:

private readonly Func<IDependancy> _dependancy;
public MyService(Func<IDependancy> dependancy)
{
    _dependancy = dependancy;
}

public Message Method1()
{
    _dependancy().DoSomething();
}

public Message Method2()
{
    _dependancy().DoSomething();  
}

public Message Method3()
{
    _dependancy().DoSomething();  
}

А потом:

var service = new MyService(() => new SomeConcreteDependency());
service.Method1();
service.Method2();
service.Method3();
1 голос
/ 10 января 2011

Первые две идеи, которые приходят мне в голову:

  1. Не принимайте это в конструкторе, но принимайте его в каждом методе.
  2. Вместо того, чтобы передавать экземпляр в конструктор, передайте фабрику или Func<IDependency>, который будет создавать новый экземпляр при каждом вызове функции.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...