前言
回顾上篇的设计模式之-简单工厂模式 我们可以从中发现一些问题。
先看看以计算器为例的简单工厂的结构图如下:
那此时我们换成工厂模式呢?我们先看看工厂的结构图:
承接上篇计算器为例,我们需要新建一个工厂接口
/// <summary> /// 构建一个工厂接口 /// </summary> interface IFactory { Operaion CreateOperation(); }
然后呢,为加减乘法各建一个具体的工厂实现接口
//然后加减乘法各建一个具体的工厂实现接口 class AddFactory : IFactory { public Operaion CreateOperation() { return new OpertionAdd(); } } class SubFactory : IFactory { public Operaion CreateOperation() { return new OperationSub(); } } class MulFactory : IFactory { public Operaion CreateOperation() { return new OperationMul(); } } class DivFactory : IFactory { public Operaion CreateOperation() { return new OperationDiv(); } }
客户端调用
static void Main(string[] args) { try { Console.Write("请输入数字A:"); string strNumberA = Console.ReadLine(); Console.Write("请选择运算符号(+、-、*、/):"); string strOperate = Console.ReadLine(); Console.Write("请输入数字B:"); string strNumberB = Console.ReadLine(); //调用工厂进行计算 IFactory operFactory = new AddFactory(); Operaion oper = operFactory.CreateOperation(); oper.NumberA =double.Parse(strNumberA); oper.NumberB =double.Parse(strNumberB); //返回计算结果 var strResult = oper.GetResult(); Console.WriteLine("结果是:" + strResult); Console.ReadKey(); } catch (Exception ex) { Console.WriteLine("您的输入有错:" + ex.Message); } }
Why?为什么要这么写呢?上一篇的简单工厂已经很容易就实现了这个效果,为什么还要新加这个工厂来“复杂”化这个问题呢?
其实不然,简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了具体产品的依赖。
就像计算器,客户端不用管该用哪个类的实例,只需要把"+"给工厂,工厂自动就给出了相应的实例,客户端只要去做运算就可以了。但问题也在这里,如果要加一个‘求M数的N次方’功能,我们是一定要给运算工厂类的方法里加‘Case’分支条件的,既是修改了原有的类。这样就违背了我们开放-封闭原则。于是工厂方法就来了
这样的话,我们要增加‘求M数的N次方’的功能时,就不需要更改原有的工厂类了,只需要增加此功能的运算类和相应的工厂类就可以了。这就完全符合开放-封闭原则。
巩固
以大学生学习‘雷锋’好人好事为例。首先是雷锋类:拥有扫地、洗衣、买米等方法
//雷锋类 class LeiFeng { public void Sweep() { Console.WriteLine("扫地"); } public void Wash() { Console.WriteLine("洗衣"); } public void BuyRice() { Console.WriteLine("买米"); } }
然后‘学雷锋大学生’类继承‘雷锋’类
/// <summary> /// 学雷锋的大学生,继承‘雷锋’ /// </summary> class Undergraduate : LeiFeng { }
然后客户端实现
LeiFeng xueleifeng = new Undergraduate(); xueleifeng.BuyRice(); xueleifeng.Sweep(); xueleifeng.Wash();
有一个问题,如果有三个人去学‘雷锋做好事,该怎么写呢?’
难道是写成?
LeiFeng xueleifeng = new Undergraduate(); xueleifeng.BuyRice(); LeiFeng xueleifeng2 = new Undergraduate(); xueleifeng.Sweep(); LeiFeng xueleifeng3 = new Undergraduate(); xueleifeng.Wash();
此时,就非常不合适了,老人不需要知道是谁来做好事,他只需要知道学雷锋的人来帮忙就可以ile,这样写我们需要更改多个实例化的地方。我们应该增加‘社区志愿者’类
/// <summary> /// 社区志愿者 /// </summary> class Volunteer : LeiFeng { }
再写简单工厂类
/// <summary> /// 简单雷锋工厂 /// </summary> class SimpleFactory { public static LeiFeng CreateLeiFeng(string type) { LeiFeng result = null; switch (type) { case "学雷锋的大学生": result = new Undergraduate(); break; case "社区志愿者": result=new Volunteer(); break; } return result; } }
客户端的代码,如果要换,就只需要换‘学雷锋的大学生为‘社区志愿者’’
//简单工厂模式 LeiFeng studentA = SimpleFactory.CreateLeiFeng("学雷锋的大学生"); studentA.BuyRice(); LeiFeng studentB = SimpleFactory.CreateLeiFeng("学雷锋的大学生"); studentA.Sweep(); LeiFeng studentC = SimpleFactory.CreateLeiFeng("学雷锋的大学生"); studentA.Wash();
好,此时我们就发现,在任何实例化的时候写出这个工厂的代码,这里有重复,就出现了坏的味道,此时,我们再用工厂模式写一遍。
/// <summary> /// 雷锋工厂 /// </summary> interface IFactory { LeiFeng CreateLeiFeng(); } /// <summary> /// 学雷锋的大学生工厂 /// </summary> class UndergraduateFacotry : IFactory { public LeiFeng CreateLeiFeng() { return new Undergraduate(); } } /// <summary> /// 社区志愿者工厂 /// </summary> class VolunteerFactory : IFactory { public LeiFeng CreateLeiFeng() { return new Volunteer(); } }
客户端调用的时候只需要如下就可以了
//工厂方法模式 IFactory factory = new UndergraduateFacotry();//要换成‘社区志愿者’,修改这里即可 LeiFeng student = factory.CreateLeiFeng(); student.BuyRice(); student.Sweep(); student.Wash();
小结
工厂方法克服了简单工厂违背开放-封闭原则的缺点,又保持了封装对象创建过程的优点。
但以上并不是最佳做法,利用‘反射’可以解决避免分支判断的问题。
未完待更新。。。。