在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
类的底层实现, 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。 我可以通过创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有这样的概念。
- 编写unit testing在ASP.NET Web API中使用User.Identity.Name的方法
- 为什么List.Sort()是一个实例方法,但Array.Sort()是静态的?
- 使用.NET 4.5 HttpClient的代理
- 在我的两个屏幕之一的DataGridView可怕的重绘性能
- 我需要在.NET中使用Microsoft.Office.Interop.Excel?
- AppDomain和MarshalByRefObject的生命时间:如何避免RemotingException?
- 识别NHibernate代理类
- 在C#中input按键
- 在DataGridView中显示导航属性的属性(二级属性)