在Bootstrapper中配置Automapper违反了开放封闭原则?

Omu*_*Omu 35 .net bootstrapping automapper open-closed-principle solid-principles

我在引导程序配置Automapper和我打电话Bootstrap()Application_Start(),我一直在说,这是错误的,因为我要修改我的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>();
    }    
}
Run Code Online (Sandbox Code Playgroud)

mry*_*ren 39

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

您违反了SRP,因为bootstrapping类有多个原因需要更改:如果您更改模型绑定或自动映射器配置.

如果要添加其他引导代码以配置系统的另一个子组件,则会违反OCP.

我通常如何处理这个是我定义以下界面.

public interface IGlobalConfiguration
{
    void Configure();
}
Run Code Online (Sandbox Code Playgroud)

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

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.
    }
}
Run Code Online (Sandbox Code Playgroud)

我使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,我将以下代码添加到Global.asax文件中.

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

        Kernel.Get<IGlobalConfiguration>().Configure();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我的引导代码遵循SRP和OCP.我可以通过创建实现IGlobalConfiguration接口的类来轻松添加其他引导代码,而我的全局配置类只有一个原因需要更改.

  • 但这不会违反OCP.OCP不会再次写入.OCP声明引导代码的使用者GlobalConfigurationModule(GCM)应该依赖抽象而不是实现.如果我要为log4net添加bootstrapping,我将创建一个实现IGlobalConfiguration的类Log4NetGlobalConfiguration类.但是,我不必修改我的代码的任何其他部分,绝对不是GCM,因为它没有复杂的IGlobalConfiguration接口实现的知识. (10认同)
  • 每次需要添加新映射时,您仍需要在AutoMapperGlobalConfiguration中更改Configure方法 (3认同)