写给准备跳槽的小伙伴们的设计模式——工厂方法设计模式
2023-03-20 15:20:17 时间
概述
工厂方法模式(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);
总结
一个四则运算的需求,分别采用简单工厂和工厂方法实现,其实各有优缺点,使用哪种设计模式主要取决于自己的业务,有何疑问,欢迎交流。
相关文章
- 金融服务领域的大数据:即时分析
- 影响大数据、机器学习和人工智能未来发展的8个因素
- 从0开始构建一个属于你自己的PHP框架
- 如何将Hadoop集成到工作流程中?这6个优秀实践必看
- SEO公司使用大数据优化其模型的5种方法
- 关于Web Workers你需要了解的七件事
- 深入理解HTTPS原理、过程与实践
- 增强分析:数据和分析的未来
- PHP协程实现过程详解
- AI专家:大数据知识图谱——实战经验总结
- 关于PHP的错误机制总结
- 利用数据分析量化协同过滤算法的两大常见难题
- 怎么做大数据工作流调度系统?大厂架构师一语点破!
- 2019大数据处理必备的十大工具,从Linux到架构师必修
- OpenCV中的KMeans算法介绍与应用
- 教大家如果搭建一套phpstorm+wamp+xdebug调试PHP的环境
- CentOS下三种PHP拓展安装方法
- Go语言HTTP Server源码分析
- Go语言HTTP Server源码分析
- 2017年4月编程语言排行榜:Hack首次进入前五十