Проблема, которую вы описываете, состоит в том, что у вас много форм, но во время выполнения вам нужна одна конкретная форма, и поэтому вы не хотите внедрять все формы.Это может быть хорошим сценарием для абстрактной фабрики.
Мы часто представляем фабрику как интерфейс с одним методом, но мы также можем сделать это с делегатом:
public delegate IForm GetFormByTypeFunction(FormType formType);
Теперьваш класс выглядит так:
public class ApplicationForms : IApplicationForms
{
private readonly GetFormByTypeFunction _getFormByType;
public ApplicationForms(GetFormByTypeFunction getFormByType)
{
_getFormByType = getFormByType;
}
public void SubmitApplicationForm(FormData data)
{
var form = _getFormByType(data.FormType);
form.CreateNewForm(data);
}
}
Теперь вопрос заключается в том, как реализовать фабрику.Возможно, у него все еще есть выражение switch
или что-то не слишком элегантное, но это нормально.Суть фабрики в том, что, как бы она ни работала, бизнес по созданию и / или выбору реализации переносится из класса, который зависит от реализации.
Вы можете зарегистрировать делегата в Autofac следующим образом:
builder.Register<GetFormByTypeFunction>(context => formType =>
{
switch (formType)
{
case FormType.Type1:
{
return context.Resolve<FormOne>();
}
case FormType.Type2:
{
return context.Resolve<FormTwo>();
}
default:
throw new InvalidOperationException("Unknown form type");
}
});
Теперь вам не нужно разрешать все реализации IForm
заранее, потому что вы можете разрешить тот, который вы хотитенепосредственно из контейнера, если вы знаете, какой вы хотите.
Это может показаться "неправильным", потому что вы решаете из контейнера.Но вы не решаете напрямую из контейнера.Вы зависите от завода.Эта фабрика может быть заменена любой другой реализацией, что означает, что ваш класс не зависит от контейнера.
Этот тип фабрики также очень легко подделать.Технически это даже не издевательство.Это просто реализация фабрики, которая возвращает макет.
var formMock = new Mock<IForm>();
var factory = new GetFormByTypeFunction(formType => formMock.Object);