Сначала позвольте мне кратко описать структуру, а затем я предоставлю вам упрощенный пример.
Описание структуры.
- Пользователь отправляет строковый запрос ->
- Программа определяет IRequestContext и ICommand ->
- вызывается ->
Код: Выделить всё
ICommand.Execute(IRequestContext) - При выполнении создаются IStep[] и IPlan(IStep[]) через фабрику и отправляются в планировщик ->< /li>
В определенное время планировщик запускает IPlan с IRequestContext. - выполняется шаг за шагом путем вызова IObservable IStep.Make(IRequestContext) ->
Код: Выделить всё
IPlan - Реализации IStep содержат экземпляры буфера для совместного использования результат их выполнения в рамках текущего плана. Он не возвращается, но необходимо сформировать итоговый отчет, но не только для этого. У буфера не может быть интерфейса, потому что это все-таки хранилище данных.
- содержит перечисление Result и IMessageBuilder. В IMesageBuilder есть только 1 метод Build().
Код: Выделить всё
Report
Каждый класс имеет множество зависимостей, таких как интерфейсы для работы с базой данных, локализация, API связи. Эти зависимости регистрируются в корне композиции. В данном случае это не проблема.
Экземпляр IRequestContext создается во время выполнения для каждого запроса пользователя. От него зависят IStep, IMessageBuilder и всевозможные буферы. Поэтому я не могу просто зарегистрировать SomeMessageBuilder, потому что необходимые данные для построителя создаются во время выполнения шага. И разные запросы не могут использовать один и тот же экземпляр построителя сообщений или буфера.
Для каждой реализации IMessageBuilder будет разное количество и типы параметров. Вот почему я не могу изменить интерфейс, чтобы принимать такие объекты, как IMessageBuilder.Build(Entity1, Entity2, ...). Поэтому мне приходится создавать и регистрировать фабрики для каждой реализации IMessageBuilder. В результате каждая реализация IStep зависит от IFactory.
Каждая реализация IPlan имеет это собственная фабрика, которая создает уникальную комбинацию шагов. Кроме того, я использую реализацию составного шаблона для таких шагов, как CompositeStep(IStep[] шаг) : IStep. Поэтому мне необходимо зарегистрировать фабрику для каждой реализации IStep, и мне нужно зарегистрировать фабрику для каждого CompositeStep, который состоит из разных шагов.
Упрощенный пример
Упрощенный пример
Упрощенный пример h3>
Имейте в виду, что у меня есть дюжина различных реализаций IPlan, которые могут использовать одни и те же шаги.
Некоторые интерфейсы и классы для пояснения.< /p>
Код: Выделить всё
public interface IPlan{
IObservable Execute(TContext context);
bool IsReadyToGoNext(TReport report);
}
public interface IStep{
IObservable Make(TContext context);
}
public interface IFactory
{
TObject Create(T1 param);
}
public interface IMessageBuilder{
SendMessage Build();
}
public class CreateMessageBuilder : LocalizedMessageBuilder, IMessageBuilder
{
public CreateMessageBuilder(long chatId, CultureInfo info
, ILocalizationProvider localizationProvider, int minSymbols, int maxSymbols)
{...}
public void SetUser(UserRepresentation representation){...};
public void SetSirena(SirenRepresentation sirena){...};
public void IsUserAllowedToCreateSirena(bool isAllowed){...};
public void IsTitleValid(bool isValid){...};
public override SendMessage Build(){...};
}
Код: Выделить всё
public class CreateSirenaPlanFactory : IFactory
{
private readonly Container container;
private readonly IFactory messageBuilderFactory;
private readonly IFactory bufferFactory;
public CreateSirenaPlanFactory(Container container
, IFactory messageBuilderFactory
, IFactory bufferFactory)
{
this.container = container;
this.messageBuilderFactory = messageBuilderFactory;
this.bufferFactory = bufferFactory;
}
public IPlan Create(IRequestContext context)
{
CreateMessageBuilder messageBuilder = messageBuilderFactory.Create(context);
CreateSirenaStep.Buffer buffer = bufferFactory.Create(messageBuilder);
//Same buffer instance has to be shared between group of steps below
//But for each new request a new instance of plan and of buffer has to be created
var validation = new CompositeCommandStep([
container.GetInstance(),
container.GetInstance()
]);
IStep[] steps = [
container.GetInstance(),
validation,
container.GetInstance(),
];
return new CommandPlan(CreateSirenaCommand.NAME,steps);
}
}
Как это привязать? Я не хочу создавать фабрику для каждой реализации IStep, которая зависит от одного и более параметров, создаваемых во время выполнения. И я вообще не знаю, как привязать буфер в этой ситуации, поскольку у SimpleInjector нет контекста.
P.S.
Когда я работал с движком Unity и с Zenject/ В Extenject было гораздо больше возможностей разделить контексты привязок и создать условные привязки для экземпляров из определенной фабрики. Жаль, что в SimpleInjector нет таких инструментов.
Потому что для каждого экземпляра плана я мог создать контекст. И для каждого контекста будет создан 1 экземпляр буфера. Более того, мне не нужно создавать фабрику для каждого экземпляра, которому нужны параметры, потому что я могу просто связать собственную фабрику с параметрами. Для меня было огромным удивлением, когда я узнал, что документация не предоставляет информацию о контексте, а только об областях видимости. Но я не могу создать экземпляр буфера в области, потому что область будет закрыта, когда метод Create завершит свою работу, и экземпляр будет удален, как я понял из документации. Возможно, я могу использовать область Flowing, однако я до сих пор не понимаю, как разрешить экземпляр с параметрами.
Подробнее здесь: https://stackoverflow.com/questions/787 ... ld-be-eval
Мобильная версия