3

写给准备跳槽的小伙伴们的设计模式——工厂方法设计模式 - realyrare

 1 year ago
source link: https://www.cnblogs.com/mhg215/p/17119131.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

工厂方法模式(FactoryMethod),定义一个创建产品对象的工厂接口,让工厂子类决定实例化那一个产品类。我们把被创建的对象称为“产品”,把创建产品的对象称为“工厂”。如果要创建的产品不多,只要一个工厂类就可以完成,这种模式叫“简单工厂模式”,它不属于 23 种经典设计模式,它的缺点是增加新产品时会违背“开闭原则”(可以通过反射克服该缺点)。

工厂方法模式是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。


我们先来看一看这样一个案例,小学生玩的四则运算,当客户输入两个数,然后输入一个操作符,获得结果!我们先用简单工厂写下逻辑代码,验证下简单工厂的缺点。

简单工厂代码

   /// <summary>
    ///  静态工作方法 实际上就是把创建对象的过程放到静态方法里面
    /// </summary>
    public class CalFactory
    {
        public static ICalculator GetCalculator(string oper)
        {
            ICalculator? calculator = null;
            switch (oper)
            {
                case "*":
                    calculator = new Mul();
                    break;
                case "+":
                    calculator = new Add();
                    break;
                case "-":
                    calculator = new Sub();
                    break;
                case "/":
                    calculator = new Div();
                    break;
            }
            return calculator;
        }
    }
   public interface  ICalculator
    {
        double GetResult(double d1,double d2);
    }

    public class Add : ICalculator
    {
        public double GetResult(double d1, double d2)
        {
           return d1+ d2;   
        }
    }
    public class Sub : ICalculator
    {
        public double GetResult(double d1, double d2)
        {
            return d1-d2;
        }
    }
    public class Mul : ICalculator
    {
        public double GetResult(double d1, double d2)
        {
            return d1* d2;
        }
    }
    public class Div : ICalculator
    {
        public double GetResult(double d1, double d2)
        {
            return d1 / d2;
        }
//C# 控制台调用
Console.WriteLine("简单工厂设计模式!");
Console.WriteLine("请输入操作数1");
var d1 = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("请输入操作数2");
var d2 = Convert.ToDouble(Console.ReadLine());
ICalculator calculator = null;
Console.WriteLine("请输入操作符");
string flag=Console.ReadLine();

calculator= CalFactory.GetCalculator(flag);   
double reslut= calculator.GetResult(d1,d2);
Console.WriteLine(reslut);

这个需求的代码逻辑很简单,一看基本就会,我们主要说下简单工厂模式的优缺点;

1、简单工厂设计模式解决了客户端直接依赖具体对象的问题,客户端消除了创建对象的责任,仅仅承担使用的责任。简单工厂模式实现了对责任的分割;
2、简单工厂起到了代码复用的作用;
缺点:
1、系统扩展困难,一旦加入新功能,就必须要修改工厂逻辑。破坏了开闭原则;
2、简单工厂集合了多有创建对象的逻辑,一旦不能正常工作,会导致整个系统出问题;

工厂方法代码

还是上面的需求,我们定义一个创建对象的接口,让子类决定实例化哪一个类。

    public interface ICalFactory
    {
        ICalculator GetCalculator();
    }
    public class MulFactory : ICalFactory
    {
        public ICalculator GetCalculator()
        {
            return new Mul();
        }
    }
  public class AddFactory : ICalFactory
    {
        public ICalculator GetCalculator()
        {
            return new Add();
        }
    }
  public class SubFactory : ICalFactory
    {
        public ICalculator GetCalculator()
        {
            return new Sub();
        }
    }
    public class DivFactory : ICalFactory
    {
        public ICalculator GetCalculator()
        {
            return new Div();
        }
    }
   public interface ICalculator
    {
        double GetResult(double d1, double d2);
    }

    public class Add : ICalculator
    {
        public double GetResult(double d1, double d2)
        {
            return d1 + d2;
        }
    }
    public class Sub : ICalculator
    {
        public double GetResult(double d1, double d2)
        {
            return d1 - d2;
        }
    }
    public class Mul : ICalculator
    {
        public double GetResult(double d1, double d2)
        {
            return d1 * d2;
        }
    }
    public class Div : ICalculator
    {
        public double GetResult(double d1, double d2)
        {
            return d1 / d2;
        }
    }
//C# 控制台调用
Console.WriteLine("请输入操作数1");
var d1 = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("请输入操作数2");
var d2 = Convert.ToDouble(Console.ReadLine());

Console.WriteLine("请输入操作符");
string flag = Console.ReadLine();

ICalFactory? calFactory = null;

switch (flag)
{
    case "*":
        calFactory = new MulFactory();
        break;
    case "+":
        calFactory = new AddFactory();
        break;
    case "-":
        calFactory = new SubFactory();
        break;
    case "/":
        calFactory = new DivFactory();
        break;
}

ICalculator calculator=calFactory?.GetCalculator();
var result= calculator.GetResult(d1, d2);
Console.WriteLine(result);

我们目前是使用了工厂方法设计模式来实现了需求,但能看到源码里面有一坨switch case,我们接下来通过反射处理switch case

没有switch case的工厂方法代码

 public class OperFactory:Attribute
    {
        public string  Oper { get;  }
        public OperFactory(string value)
        {
            Oper=value;
        }
    }
  public class ReflectionFactory
    {
        //根据用户输入的操作符 返回一个对象
        Dictionary<string, ICalFactory> dic=new Dictionary<string, ICalFactory>();
        public ReflectionFactory()
        {
            //拿到当前正在运行的程序集
            Assembly assembly= Assembly.GetExecutingAssembly();
            foreach (var item in assembly.GetTypes())
            {
                //IsAssignableFrom 表示item继承了ICalFactory或实现了ICalFactory
                if (typeof(ICalFactory).IsAssignableFrom(item)&&!item.IsInterface)
                {
                    OperFactory of= item.GetCustomAttribute<OperFactory>();
                    if (of != null)
                    {
                        //给键值对集合赋值
                        dic[of.Oper] = Activator.CreateInstance(item) as ICalFactory;
                    }
                }
            }
        }

        public ICalFactory GetFac(string s)
        {
            if (dic.ContainsKey(s))
            {
                return dic[s];
            }
            return null;
        }
    }
   public interface ICalFactory
    {
        ICalculator GetCalculator();
    }
    [OperFactory("*")]
    public class MulFactory : ICalFactory
    {
        public ICalculator GetCalculator()
        {
            return new Mul();
        }
    }
    [OperFactory("+")]
    public class AddFactory : ICalFactory
    {
        public ICalculator GetCalculator()
        {
            return new Add();
        }
    }
    [OperFactory("-")]
    public class SubFactory : ICalFactory
    {
        public ICalculator GetCalculator()
        {
            return new Sub();
        }
    }
    [OperFactory("/")]
    public class DivFactory : ICalFactory
    {
        public ICalculator GetCalculator()
        {
            return new Div();
        }
    }
//C# 控制台调用
ReflectionFactory reflectionFactory = new ReflectionFactory();
ICalFactory calFactory2=  reflectionFactory.GetFac(flag);
 var result2= calFactory2.GetCalculator().GetResult(d1, d2);
Console.WriteLine(result2);

一个四则运算的需求,分别采用简单工厂和工厂方法实现,其实各有优缺点,使用哪种设计模式主要取决于自己的业务,有何疑问,欢迎交流。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK