在引导程序配置Automapper违反了开放封闭原则? [英] Configuring Automapper in Bootstrapper violates Open-Closed Principle?

查看:265
本文介绍了在引导程序配置Automapper违反了开放封闭原则?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在引导程序配置Automapper,我称之为引导()的Application_Start(),和有人告诉我,这是错误的,因为我每一次我一定要添加一个新的映射来修改我的引导程序类,所以我违反了开闭原则。

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

 公共静态类引导程序
{
    公共静态无效的自举()
    {
        ModelBinders.Binders.DefaultBinder =新MyModelBinder();
        InputBuilder.BootStrap();
        ConfigureAutoMapper();
    }

    公共静态无效ConfigureAutoMapper()
    {
        Mapper.CreateMap<使用者,UserDisplay>()
            .ForMember(O => o.UserRolesDescription,
                       OPT => opt.ResolveUsing&其中; RoleValueResolver>());
        Mapper.CreateMap&所述;组织,OrganisationDisplay>();
        Mapper.CreateMap&所述;组织,OrganisationOpenDisplay>();
        Mapper.CreateMap&所述; OrganisationAddress,OrganisationAddressDisplay>();
    }
}
 

解决方案

我认为,你违反了两个原则:单一职责原则(SRP)和开/闭原则(OCP)

正在违反SRP,因为自举类有多个理由去改变。如果你改变模型绑定或自动映射器配置。

您就违反了OCP,如果你要添加额外的引导code,用于配置系统的其他子组件。

我通常如何处理这是我定义如下界面。

 公共接口IGlobalConfiguration
{
    无效配置();
}
 

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

 公共类AutoMapperGlobalConfiguration:IGlobalConfiguration
{
    私人只读的IConfiguration配置;

    公共AutoMapperGlobalConfiguration(的IConfiguration配置)
    {
        this.configuration =配置;
    }

    公共无效配置()
    {
        //添加AutoMapper配置在这里。
    }
}

公共类ModelBindersGlobalConfiguration:IGlobalConfiguration
{
    私人只读ModelBinderDictionary粘合剂;

    公共ModelBindersGlobalConfiguration(ModelBinderDictionary粘合剂)
    {
        this.binders =粘合剂;
    }

    公共无效配置()
    {
        //把这里的模型绑定配置。
    }
}
 

我用Ninject注入的依赖。 的IConfiguration 是静态的底层实现 AutoMapper 类和 ModelBinderDictionary ModelBinders.Binder 对象。然后,我会定义一个 NinjectModule 将扫描指定组件实现 IGlobalConfiguration 接口的类并添加这些类到的复合物。

 公共类GlobalConfigurationModule:NinjectModule
{
    私人只读装配组件;

    公共GlobalConfigurationModule()
        :这个(Assembly.GetExecutingAssembly()){}

    公共GlobalConfigurationModule(装配组装)
    {
        this.assembly =组装;
    }

    公众覆盖无效负载()
    {
        GlobalConfigurationComposite复合=
            新GlobalConfigurationComposite();

        IEnumerable的<类型>类型=
            。assembly.GetExportedTypes()GetTypeOf< IGlobalConfiguration>()
                .SkipAnyTypeOf&其中; IComposite&其中; IGlobalConfiguration>>();

        的foreach(在类型VAR型)
        {
            IGlobalConfiguration配置=
                (IGlobalConfiguration)Kernel.Get(类型);
            composite.Add(配置);
        }

        绑定< IGlobalConfiguration>()ToConstant(复合)。
    }
}
 

我会再添加以下code到Global.asax文件。

 公共类MvcApplication:的HttpApplication
{
    公共无效的Application_Start()
    {
        的iKernel内核=新StandardKernel(
            新AutoMapperModule(),
            新MvcModule(),
            新GlobalConfigurationModule()
        );

        Kernel.Get< IGlobalConfiguration>()配置()。
    }
}
 

现在我的引导code坚持既SRP和OCP。我可以很容易地创建实现 IGlobalConfiguration 接口和我​​的全球配置类的类添加额外的引导code只能有一个理由去改变。

I am configuring Automapper in the Bootstrapper and I call the Bootstrap() in the Application_Start(), and I've been told that this is wrong because I have to modify my Bootstrapper class each time I have to add a new mapping, so I am violating the Open-Closed Principle.

How do you think, do I really violate this principle?

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>();
    }    
}

解决方案

I would argue that you are violating two principles: the single responsibility principle (SRP) and the open/closed principle (OCP).

You are violating the SRP because the bootstrapping class have more than one reason to change: if you alter model binding or the auto mapper configuration.

You would be violating the OCP if you were to add additional bootstrapping code for configuring another sub-component of the system.

How I usually handle this is that I define the following interface.

public interface IGlobalConfiguration
{
    void Configure();
}

For each component in the system that needs bootstrapping I would create a class that implements that interface.

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.
    }
}

I use Ninject to inject the dependencies. IConfiguration is the underlying implementation of the static AutoMapper class and ModelBinderDictionary is the ModelBinders.Binder object. I would then define a NinjectModule that would scan the specified assembly for any class that implements the IGlobalConfiguration interface and add those classes to a composite.

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);
    }
}

I would then add the following code to the Global.asax file.

public class MvcApplication : HttpApplication
{
    public void Application_Start()
    {
        IKernel kernel = new StandardKernel(
            new AutoMapperModule(),
            new MvcModule(),
            new GlobalConfigurationModule()
        );

        Kernel.Get<IGlobalConfiguration>().Configure();
    }
}

Now my bootstrapping code adheres to both SRP and OCP. I can easily add additional bootstrapping code by creating a class that implements the IGlobalConfiguration interface and my global configuration classes only have one reason to change.

这篇关于在引导程序配置Automapper违反了开放封闭原则?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆