• 设计模式(五) 简单工厂模式+工厂模式


    简单工厂模式

       创建一个工厂类,对实现了同一个接口的多个类进行实例的创建。

    //抽象类 人
    public abstract class HuMan
    {
            public abstract void Talk();
    }
    //黑人实现类
    public class BlackHuman : HuMan
    {
        public override void Talk()
        {
            Console.WriteLine("I am BlackHuman");
        }
    }
    //白人实现类
    public class WhiteHuman : HuMan
    {
        public override void Talk()
        {
            Console.WriteLine("I am WhiteHuman");
        }
    }
    /// <summary>
    /// 简单工厂
    /// </summary>
    public static class HumanFactory
    {
        public static HuMan CreateHuman(HumanEnum humanEnum)
        {
            HuMan huMan = null;
            switch (humanEnum)
            {
                case HumanEnum.Black:
                    huMan = new BlackHuman();
                    break;
                case HumanEnum.White:
                    huMan = new WhiteHuman();
                    break;
                default:
                    throw new NullReferenceException();
            }
            return huMan;
        }
    }
    
    //客户端调用
    //创建一个白人
    var whiteHuman1 =  SimpleFactory.CreateHuman(HumanEnum.White);
    whiteHuman1.Talk();
    //创建一个黑人
    var blackHuman1 = SimpleFactory.CreateHuman(HumanEnum.Black);
    blackHuman1.Talk();
    View Code

       优点:工厂中包含了必要的逻辑判断,根据客户端的选择条件动态的创建相关的类,对于客户端来说,它只需要提供创建实现类的参数,隐藏了创建实例的细节,去除了对具体实现类的依赖。

       缺点:当要新增一个实现类时,需要修改工厂类的代码(switch下增加一个Case),违背了开放-封闭原则。

    当然上面的代码其实还存在很大的优化空间,我们可以先看下工厂模式的实现方案,对比下两种模式上的区别。

    工厂模式

       定义一个用于创建对象的接口,让子类决定实现哪个类。工厂方法将创建对象实例的职责移交给了子类。

    //定义一个创建人类的工厂接口
    public interface IHumanFactory
    {
        HuMan CreateHuman();
    }
    //定义一个创建白人的工厂
    public class WhiteHumanFactory : IHumanFactory
    {
        public HuMan CreateHuman()
        {
            return new WhiteHuman();
        }
    }
    //定义一个创建黑人的工厂
    public class BlackHumanFactory : IHumanFactory
    {
        public HuMan CreateHuman()
        {
            return new BlackHuman();
        }
    }
    //客户端调用
     var whiteHumanFactory = new WhiteHumanFactory();
    var whiteHuman2 =  whiteHumanFactory .CreateHuman();
    whiteHuman2.Talk();
    var blackHumanFactory = new BlackHumanFactory();
    var blackHuman2 = blackHumanFactory .CreateHuman();
    blackHuman2.Talk();
    View Code

    优点:当要新增一个实现类时,只需要再增加一个实现类和创建实现类的工厂,不需要修改原有工厂的代码,保留了简单工厂对创建实例的封装,又体现了开放-封闭原则。

    缺点:客户端需要决定实例化哪一个工厂来创建实现类,增加了客户端的复杂度。同时每增加一个实现类,也要增加一个工厂类,增加了代码复杂度。

    简单工厂+反射

      可以通过反射技术来强化简单工厂,让简单工厂同样符合开放封闭原则。

    /// <summary>
    /// 简单工厂
    /// </summary>
    public static class HumanFactory
    {
        public static HuMan CreateHuman(string humanType)
        {
             var a = Assembly.LoadFrom($"{AppDomain.CurrentDomain.BaseDirectory}DesignPatterns.Model.dll");
            return (HuMan)a.CreateInstance($"DesignPatterns.Model.Factory.{humanType}");
        }
    }
    View Code

    客户端可以通过配置文件或者数据库中获取humanType(在程序或者数据库中维护一个参数类型+类名的字典),通过反射技术动态的创建实例。

    简单工厂+依赖注入

    //工厂类
    public class HumanFactory
    {
        private readonly Func<HumanEnum, Human> _func;
        public HumanFactory(Func<HumanEnum, Human> func)
        {
            this._func = func;
        }
        public Human  CreateHuman(HumanEnum humanEnum)
        {
            return _func(humanEnum);
        }
    }
    
    public static class HunmanDependencyInjection
    {
           //维护一个实现类的字典
        private static Dictionary<HumanEnum, Type> dicHuman = new Dictionary<QRCodeType, Type>() {
            {  HumanEnum.White,typeof(WhiteHuman)},
            { HumanEnum.Black,typeof(BlackHuman)}
        };
        public static void AddHuman(this IServiceCollection serviceCollection)
        {
            serviceCollection.AddScoped<WhiteHuman>();
            serviceCollection.AddScoped<BlackHuman>();
            serviceCollection.AddScoped(factory=> {
                Func<HumanEnum, Human> func = humanType=> {
                    return (Human)factory.GetService(dicHuman [humanType]);
                };
                return func;
            });
            serviceCollection.AddScoped<HumanFactory>();
        }
    }
    //在Startup中注入实现类和工厂
    public void ConfigureServices(IServiceCollection services)
    {
               services.AddHuman();
              services.AddMvc(); 
    }
    //客户端在构造函数中引入HumanFactory
     var  whiteHuman =  HumanFactory.CreateHuman(HumanEnum.White);
    whiteHuman.Talk();
    View Code

    这样我们就用Ioc实现了一个简单工厂,上面的代码示例是将实现类的字典放在工厂中维护,其实可以将字典放到配置文件或者数据库中维护,这样我们再增加新的实现类时,就不需要在修改工厂的代码,实现了实现类的动态扩展。也体现了开闭原则。

  • 相关阅读:
    Python eval 函数妙用
    day19 装饰器
    Struts08---全局结果和全局异常的配置
    Struts07---访问servlet的API
    Struts06---通配符的使用
    Struts05---动态查询
    Struts04---命名空间的查询顺序以及默认执行的Action
    Struts03---参数传递
    Struts02---实现struts2的三种方式
    struts2文件上传和下载
  • 原文地址:https://www.cnblogs.com/jasonbourne3/p/14099858.html
Copyright © 2020-2023  润新知