Я бы сказал, что вы нарушаете два принципа: принцип единой ответственности (SRP) и принцип открытого/закрытого (OCP).
Вы нарушаете SRP, потому что класс начальной загрузки имеет более чем одну причину изменения: если вы измените привязку модели или конфигурацию автоматического сопоставления.
Вы нарушили бы OCP, если бы вы добавили дополнительный код начальной настройки для настройки другого подкомпонента системы.
Как я обычно обрабатываю это, я определяю следующий интерфейс.
public interface IGlobalConfiguration
{
void Configure();
}
Для каждого компонента в системе, которая нуждается в самонастройке, я бы создал класс, который реализует этот интерфейс.
public class AutoMapperGlobalConfiguration : IGlobalConfiguration
{
private readonly IConfiguration configuration;
public AutoMapperGlobalConfiguration(IConfiguration configuration)
{
this.configuration = configuration;
}
public void Configure()
{
// Add AutoMapper configuration here.
}
}
public class ModelBindersGlobalConfiguration : IGlobalConfiguration
{
private readonly ModelBinderDictionary binders;
public ModelBindersGlobalConfiguration(ModelBinderDictionary binders)
{
this.binders = binders;
}
public void Configure()
{
// Add model binding configuration here.
}
}
Я использую Ninject для ввода зависимостей.IConfiguration
- это базовая реализация статического класса AutoMapper
, а ModelBinderDictionary
- объект ModelBinders.Binder
. Затем я бы определил NinjectModule
, который сканировал указанную сборку для любого класса, который реализует интерфейс IGlobalConfiguration
и добавит эти классы в композит.
public class GlobalConfigurationModule : NinjectModule
{
private readonly Assembly assembly;
public GlobalConfigurationModule()
: this(Assembly.GetExecutingAssembly()) { }
public GlobalConfigurationModule(Assembly assembly)
{
this.assembly = assembly;
}
public override void Load()
{
GlobalConfigurationComposite composite =
new GlobalConfigurationComposite();
IEnumerable<Type> types =
assembly.GetExportedTypes().GetTypeOf<IGlobalConfiguration>()
.SkipAnyTypeOf<IComposite<IGlobalConfiguration>>();
foreach (var type in types)
{
IGlobalConfiguration configuration =
(IGlobalConfiguration)Kernel.Get(type);
composite.Add(configuration);
}
Bind<IGlobalConfiguration>().ToConstant(composite);
}
}
Я бы добавил следующий код в файл Global.asax.
public class MvcApplication : HttpApplication
{
public void Application_Start()
{
IKernel kernel = new StandardKernel(
new AutoMapperModule(),
new MvcModule(),
new GlobalConfigurationModule()
);
Kernel.Get<IGlobalConfiguration>().Configure();
}
}
Теперь мой код начальной загрузки придерживается как SRP, так и OCP. Я могу легко добавить дополнительный код начальной загрузки, создав класс, который реализует интерфейс IGlobalConfiguration
, и мои глобальные классы конфигурации имеют только одну причину изменения.
, и вам все равно придется менять настройку метод в AutoMapperGlobalConfiguration каждый раз, когда вам нужно добавить новое сопоставление – Omu
Но это не нарушит OCP. OCP не пишет один раз, никогда не трогайте его снова. OCP заявляет, что потребитель кода начальной загрузки, GlobalConfigurationModule (GCM), должен полагаться на абстракцию и не выполнять конкретную реализацию. Если бы я должен был добавить загрузку для log4net, я бы создал класс класса Log4NetGlobalConfiguration, который бы реализовал IGlobalConfiguration. Тем не менее, мне не пришлось бы изменять какую-либо другую часть моего кода и, безусловно, не GCM, потому что у нее нет сложных знаний о реализации интерфейса IGlobalConfiguration. – mrydengren
Я сомневаюсь. Как только Mapper.CreateMap <>() выполняется, карты существуют до выключения приложения? – JPCF