Предположим, у меня есть тот, Service
который получает зависимости через конструктор, но также должен быть инициализирован с пользовательскими данными (контекстом), прежде чем их можно будет использовать:
public interface IService
{
void Initialize(Context context);
void DoSomething();
void DoOtherThing();
}
public class Service : IService
{
private readonly object dependency1;
private readonly object dependency2;
private readonly object dependency3;
public Service(
object dependency1,
object dependency2,
object dependency3)
{
this.dependency1 = dependency1 ?? throw new ArgumentNullException(nameof(dependency1));
this.dependency2 = dependency2 ?? throw new ArgumentNullException(nameof(dependency2));
this.dependency3 = dependency3 ?? throw new ArgumentNullException(nameof(dependency3));
}
public void Initialize(Context context)
{
// Initialize state based on context
// Heavy, long running operation
}
public void DoSomething()
{
// ...
}
public void DoOtherThing()
{
// ...
}
}
public class Context
{
public int Value1;
public string Value2;
public string Value3;
}
Теперь - данные контекста не известны заранее, поэтому я не могу зарегистрировать их как зависимость и использовать DI для внедрения их в сервис
Вот как выглядит пример клиента:
public class Client
{
private readonly IService service;
public Client(IService service)
{
this.service = service ?? throw new ArgumentNullException(nameof(service));
}
public void OnStartup()
{
service.Initialize(new Context
{
Value1 = 123,
Value2 = "my data",
Value3 = "abcd"
});
}
public void Execute()
{
service.DoSomething();
service.DoOtherThing();
}
}
Как вы можете видеть - существует временная связь и инициализация запахов кода метода, потому что сначала мне нужно позвонить, service.Initialize
чтобы иметь возможность звонить, service.DoSomething
а service.DoOtherThing
потом.
Каковы другие подходы, в которых я могу устранить эти проблемы?
Дополнительные разъяснения поведения:
Каждый экземпляр клиента должен иметь свой собственный экземпляр службы, инициализированный конкретными данными контекста клиента. Таким образом, данные контекста не являются статичными или известны заранее, поэтому они не могут быть введены DI в конструктор.
Service
есть другие , чем зависимостиContext
, которые не будут предоставлятьсяClient
, они могут быть предоставлены через DI вServiceFactory
будет приняты кService
когдаcreateService
называется.ServiceBuilder partial = new ServiceBuilder().dependency1(dependency1_1).dependency2(dependency2_1).dependency3(dependency3_1);
и остаться с частично настроенным сервисом, а затемService s = partial.context(context).build()
Initialize
Метод должен быть удален изIService
интерфейса, так как это деталь реализации. Вместо этого определите другой класс, который принимает конкретный экземпляр Service и вызывает для него метод initialize. Затем этот новый класс реализует интерфейс IService:Это держит клиентский код в неведении относительно процедуры инициализации, за исключением случаев, когда
ContextDependentService
класс инициализируется. Вы, по крайней мере, ограничиваете части своего приложения, которые должны знать об этой непростой процедуре инициализации.источник
Мне кажется, что у вас есть два варианта здесь
например.
например.
Впрыскивать фабрику - это хорошо, если вы просто хотите избежать передачи контекста в качестве параметра. Скажем, только этой конкретной реализации нужен контекст, и вы не хотите добавлять его в интерфейс
Но у вас, по сути, та же проблема: что, если у фабрики еще нет инициализированного контекста?
источник
Вы не должны зависеть от интерфейса к какому-либо контексту БД и инициализировать метод. Вы можете сделать это в конкретном конструкторе классов.
И ответом на ваш главный вопрос будет « Инъекция собственности» .
Таким образом, вы можете вызывать все зависимости с помощью Property Injection . Но это может быть огромное количество. Если это так, вы можете использовать Constructor Injection для них, но вы можете установить свой контекст по свойству, проверив, является ли он пустым.
источник
Миско Хевери имеет очень полезную запись в блоге о деле, с которым вы столкнулись. Вы оба нуждаетесь в новых и инъекционных препаратах для своего
Service
класса, и этот пост может помочь вам.источник