工厂模式:定义一个用于创建对象的接口,让子类来决定实例化哪一个类,工厂方法使一个类的实例化延迟到子类。
之前我们看过简单工厂类,使用的是计算器作为例子。代码如下:
简单工厂类Factory.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; /// 简单工厂类 namespace simpleFactory { public class Factory { public static Ireckon CreateTreckon(string signStr) { Ireckon reckon = null; switch (signStr) { case "+": reckon = new Plus(); break; case "-": reckon = new Cut(); break; case "*": reckon = new Ride(); break; default: Console.WriteLine("暂不支持您输入的运算符"); break; } return reckon; } } }
下面我们使用工厂模式来实现这个例子:
先构建一个工厂接口。
然后加减乘除各建一个具体的工厂去实现这个接口。
定义一个算法接口,一个工厂接口,算法类继承算法接口,算法工厂类继承工厂接口(每个算法类都需要有个算法工厂类来对应),将区分运算符号的逻辑部分放到客户端。我们再增加算法的时候,只需要增加对应的算法类。算法工厂类,及修改客户端即可,这样不违反开放封闭原则。
代码如下:
算法类:Ireckon.cs
namespace simpleFactory { public interface Ireckon { double getResult(double strNumberA, double strNumberB); } }
工厂类:IForecty.cs
namespace simpleFactory { public interface IForecty { /// <summary> /// 工厂类:返回计算方法 /// </summary> Ireckon CreateReckon(); } }
减法类:Cut.cs
namespace simpleFactory { public class Cut:Ireckon { public double result; public double getResult(double strNumberA, double strNumberB) { result = strNumberA - strNumberB; return result; } } }
减法工厂类:CutFactory.cs
namespace simpleFactory { public class CutFactory:IForecty { public Ireckon CreateReckon() { return new Cut(); } } }
加法类:Plus.cs
namespace simpleFactory { public class Plus:Ireckon { public double result; public double getResult(double strNumberA, double strNumberB) { result = strNumberA + strNumberB; return result; } } }
加法工厂类:PlusFactory.cs
namespace simpleFactory { public class PlusFactory:IForecty { public Ireckon CreateReckon() { return new Plus(); } } }
乘法类:Ride.cs
namespace simpleFactory { public class Ride:Ireckon { public double result; public double getResult(double strNumberA, double strNumberB) { result = strNumberA * strNumberB; return result; } } }
乘法工厂类:RideFactory.cs
namespace simpleFactory { public class RideFactory:IForecty { public Ireckon CreateReckon() { return new Ride(); } } }
客户端:Program.cs
namespace simpleFactory { class Program { static void Main(string[] args) { // 数字A double strNumberA; // 数字B double strNumberB; // 运算符 string signStr; // 运算结果 double result; try { Console.WriteLine("请输入第一个数字"); strNumberA = Convert.ToDouble(Console.ReadLine()); Console.WriteLine("请输入运算符号"); signStr = Console.ReadLine(); Console.WriteLine("请输入第二个数字"); strNumberB = Convert.ToDouble(Console.ReadLine()); // 使用简单工厂类返回实例化子类的对象(因为子类中都是重写基类中的方法,指定类型的时候,直接声明基类就可以) //Ireckon reckon = Factory.CreateTreckon(signStr); //// 调用 //result = reckon.getResult(strNumberA, strNumberB); // 工厂模式实现调用,现在我们再增加算法的时候,只需要增加对应的算法类 // 算法工厂类,及修改调用部分即可,这样不违反开放封闭原则。 IForecty reckon = null; switch (signStr) { case "+": reckon = new PlusFactory(); break; case "-": reckon = new CutFactory(); break; case "*": reckon = new RideFactory(); break; default: Console.WriteLine("暂不支持您输入的运算符"); break; } result = reckon.CreateReckon().getResult(strNumberA, strNumberB); Console.WriteLine("运算结果为:" + result); } catch (Exception qq ) { // 输出错误信息 Console.WriteLine(qq.Message); } Console.ReadLine(); } } }
上边的代码就使用工厂模式实现了简单工厂模式中的例子,代码看起来比简单工厂模式要复杂的多。但是,其更加合理。
简单工厂模式的优点:我们可以对创建的对象进行一些 “加工” ,而且客户端并不知道,因为工厂隐藏了这些细节。如果,没有工厂的话,那我们是不是就得自己在客户端上写这些代码,这就好比本来可以在工厂里生产的东西,拿来自己手工制作,不仅麻烦以后还不好维护。
但是缺点也很明显:如果需要在方法里写很多与对象创建有关的业务代码,而且需要的创建的对象还不少的话,我们要在这个简单工厂类里编写很多个方法,每个方法里都得写很多相应的业务代码,而每次增加子类或者删除子类对象的创建都需要打开这简单工厂类来进行修改。这会导致这个简单工厂类很庞大臃肿、耦合性高,而且增加、删除某个子类对象的创建都需要打开简单工厂类来进行修改代码也违反了开-闭原则。
工厂模式是对简单工厂模式进一步的解耦,因为在工厂方法模式中是一个子类对应一个工厂类,而这些工厂类都实现于一个抽象接口。这相当于是把原本会因为业务代码而庞大的简单工厂类,拆分成了一个个的工厂类,这样代码就不会都耦合在同一个类里了。
工厂模式中,要增加产品类时也要相应地增加工厂类,客户端的代码也增加了不少。工厂方法把简单工厂的内部逻辑判断转移到了客户端代码来进行。
你想要加功能,本来是改工厂类的,而现在是修改客户端。而且各个不同功能的实例对象的创建代码,也没有耦合在同一个工厂类里,这也是工厂方法模式对简单工厂模式解耦的一个体现。工厂方法模式克服了简单工厂会违背开-闭原则的缺点,又保持了封装对象创建过程的优点。
但工厂方法模式的缺点是每增加一个产品类,就需要增加一个对应的工厂类,增加了额外的开发量。
