C#设计模式(1)——简单工厂模式
1.什么是简单工厂
现实中的工厂负责生产产品,顾名思义,编程中的简单工厂就是一个生产对象的类,它的主要作用是创建具体的产品类实例。我们以一个生产鼠标为例来分析简单工厂的作用,鼠标有两种:戴尔鼠标和惠普鼠标,代码如下:
//鼠标抽象类 public abstract class Mouse { public abstract void Print(); } //戴尔鼠标 public class DellMouse : Mouse { public override void Print() { Console.WriteLine("生产了一个Dell鼠标!"); } } //惠普鼠标 public class HpMouse : Mouse { public override void Print() { Console.WriteLine("生产了一个惠普鼠标!"); } }
客户端代码:
class Program { static void Main(string[] args) { Mouse mouse1 = new DellMouse(); Mouse mouse2 = new DellMouse(); Mouse mouse3 = new DellMouse(); Mouse mouse4 = new DellMouse(); Mouse mouse5 = new DellMouse(); mouse1.Print(); } }
程序运行如下:
我们可以看到程序运行没有问题,通过new一个DellMouse我们可以创建一个戴尔的鼠标,这时有一个问题,如果我们不想要戴尔鼠标了,要全部生产惠普鼠标怎么办呢?最简单直接的方法就是把 new DellMouse全部替换成 new HpMouse 。如果我们的软件中new了100个DellMouse实例呢?一个一个地去替换会是一个巨大的工作量,同时通过new的方式来创建戴尔鼠标的实例,会让DellMouse类和客户端产生强耦合关系,这时候使用简单工厂就可以帮助我们降低耦合,减少工作量了。添加一个MouseFactory简单工厂类,这个工厂类专门来创建Mouse的实例:
/// <summary> /// 鼠标工厂类 /// </summary> public class MouseFactory { private Mouse mouse = null; public Mouse CreateMouse(string brand) { switch (brand) { case "dell": mouse = new DellMouse(); break; case "hp": mouse = new HpMouse(); break; default: break; } return mouse; } }
客户端的代码就可以改成:
class Program { static void Main(string[] args) { //实例化一个工厂类 MouseFactory mouseFactory = new MouseFactory(); //通过工厂类创建鼠标 Mouse mouse1 = mouseFactory.CreateMouse("dell"); Mouse mouse2 = mouseFactory.CreateMouse("dell"); Mouse mouse3 = mouseFactory.CreateMouse("dell"); Mouse mouse4 = mouseFactory.CreateMouse("dell"); Mouse mouse5 = mouseFactory.CreateMouse("dell"); mouse1.Print(); Console.ReadKey(); } }
运行程序结果一样的,这样做有什么好处呢?我们看到我们把以前的 new DellMouse() 替换成了 mouseFactory.Create("dell") ,客户端和DellMouse的耦合变成了 客户端<-->MouseFactory<-->DellMouse形式,有效降低了客户端和DellMouse间的耦合。我们还用一个疑问,程序改成这样的话,如果我们想把戴尔鼠标全部换成惠普鼠标,要把工厂类的参数"dell"换成"hp",不是还要改100次?任务量没有降低呀!对于这个问题,我们可以把品牌名brand存放在一个地方,如配置文件中,这样我们想切换鼠标品牌时就不用修改代码,直接修改配置文件即可,如下:
配置文件:
<appSettings> <add key="dbname" value="dell"/> </appSettings>
工厂类修改为:
/// <summary> /// 鼠标工厂类 /// </summary> public class MouseFactory { //从配置文件中读取品牌 private static readonly string brand = ConfigurationManager.AppSettings["brand"]; private Mouse mouse = null; public Mouse CreateMouse() { switch (brand) { case "dell": mouse = new DellMouse(); break; case "hp": mouse = new HpMouse(); break; default: break; } return mouse; } }
客户端代码就不用传参数了,如下:
class Program { static void Main(string[] args) { //实例化一个工厂类 MouseFactory mouseFactory = new MouseFactory(); //通过工厂类创建鼠标 Mouse mouse1 = mouseFactory.CreateMouse(); Mouse mouse2 = mouseFactory.CreateMouse(); Mouse mouse3 = mouseFactory.CreateMouse(); Mouse mouse4 = mouseFactory.CreateMouse(); Mouse mouse5 = mouseFactory.CreateMouse(); mouse1.Print(); Console.ReadKey(); } }
现在我们想把生产的鼠标都换成惠普鼠标,只需要将配置文件中的dell改成hp即可,修改配置文件后运行结果如下:
大功告成!这时有一个问题,如果我们想生产华硕鼠标怎么办呢?除了添加一个继承Mouse的AsusMouse类外,还要在MouseFactory中添加一段case 代码。按照开闭原则,添加一个实现类没什么问题,开闭原则中对添加开放;但是修改MouseFactory工厂类就违背了对修改闭合的原则了。后边的工厂模式就是专门用来解决这个问题的。
2.小结
上边例子的类图:
简单工厂的优点:
1.简单工厂可以有效地降低客户端和具体对象的耦合,将new具体对象的任务交给了一个简单工厂类
2可以有效的进行代码复用,如客户端A和客户端B都需要一个具体对象,客户端A和客户端B可以通过同一个简单工厂来获取具体类型的实例
简单工厂的缺点:
一定程度上违背了开闭原则,在新增产品时需要修改简单工厂类