在Bootstrapper中configurationAutomapper违反开放原则?

我在Bootstrapper中configuration了Automapper,我在Application_Start()调用了Bootstrap() ,而且我被告知这是错误的,因为每次我必须添加一个新映射时,必须修改Bootstrapper类,所以我我违反了开放原则。

你怎么看,我真的违反这个原则吗?

 public static class Bootstrapper { public static void BootStrap() { ModelBinders.Binders.DefaultBinder = new MyModelBinder(); InputBuilder.BootStrap(); ConfigureAutoMapper(); } public static void ConfigureAutoMapper() { Mapper.CreateMap<User, UserDisplay>() .ForMember(o => o.UserRolesDescription, opt => opt.ResolveUsing<RoleValueResolver>()); Mapper.CreateMap<Organisation, OrganisationDisplay>(); Mapper.CreateMap<Organisation, OrganisationOpenDisplay>(); Mapper.CreateMap<OrganisationAddress, OrganisationAddressDisplay>(); } } 

我认为你违反了两个原则:单一责任原则(SRP)和开放/封闭原则(OCP)。

您正在违反SRP,因为引导类有多个更改原因:如果您更改模型绑定或自动映射器configuration。

如果您要添加额外的引导代码来configuration系统的另一个子组件,那么您将违反OCP。

我通常如何处理这个问题是我定义了下面的接口。

 public interface IGlobalConfiguration { void Configure(); } 

对于需要引导的系统中的每个组件,我将创build一个实现该接口的类。

 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类的底层实现, ModelBinderDictionaryModelBinders.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。 我可以通过创build一个实现IGlobalConfiguration接口的类轻松地添加额外的引导代码,我的全局configuration类只有一个原因需要改变。

要完全closures,你可以有一个静态初始化每个映射注册,但这将是矫枉过正。

从能够进行逆向工程的angular度来看,有些东西实际上是有用的。

在NInject中,每个项目或子系统(一组项目)都有一个Module ,这似乎是一个明智的折衷。

我知道这是一个老的,但是您可能有兴趣知道我已经创build了一个名为Bootstrapper的开源库,可以正确处理这个问题。 你可能想看看。 为了避免违反OC原则,您需要在实现IMapCreater的单独类中定义映射器。 Boostrapper将使用reflection来查找这些类,并将在启动时初始化所有映射器

如果有的话,它是你违反的单一责任原则,因为class上有一个以上的理由要改变。

我个人将有一个ConfigureAutoMapper类,所有我的AutoMapperconfiguration完成。 但是可以认为这归结于个人select。

Omu,当我在应用的启动例程中引导一个IoC容器时,我遇到了类似的问题。 对于IoC,我已经给出的指导指出了集中configuration的优势,而不是在添加更改时将其散布在您的应用程序中。 为了configurationAutoMapper,我认为集中化的优势不那么重要。 如果你能把你的AutoMapper容器放到你的IoC容器或服务定位器中,我同意鲁本·巴特林克(Ruben Bartelink)对每个程序集或静态构造函数或分散的东西configuration映射的build议。

基本上,我认为这是决定你是要集中引导还是分散引导。 如果您在启动例程中担心“打开/closures”原则,请将其分散。 但是你的OCP遵守可以用来换取你在一个地方完成的所有引导的价值。 另一个select是让引导程序扫描registry的某些程序集,假设AutoMapper有这样的概念。