使用设计模式中的工厂方法模式进行C#编程的示例讲解
简介
工厂方法模式是什么?为什么要有工厂方法模式,不是有了简单工厂模式了吗?两个模式都有工厂,那有什么不同呢?功工厂方式模式是怎样实现的?ok,带着这些问题,继续看下面文章。
工厂方法模式是对简单工厂模式的扩展,可以说是用来完善简单工厂模式的缺点的,什么缺点呢?在上一篇文章已经说过:扩展性极差。你想一下,如果在简单工厂模式中,如果董事会决定想添加一个玩具生产,叫熊猫玩具,那么全厂该做的事有哪些呢?
1.告诉销售经理:我们准备要添加一个熊猫玩具,可以提供给用户的。
2.到工厂作坊里面,告诉工人要做熊猫工具。
在现实生活中确实是这样的,因为在现实生活中这样做不会造成很大的影响,但是在程序世界里面就大件事了,首先如果这样做可能会破坏工厂作坊的内部结构,造成bug,还有的是这样改就等于修改了源代码,不断添加新的工具,不断修改源代码,有没想过:如果添加100个玩具,那个判断命令里面得有多少个case啊?,程序里面不同现实生活,创建新的大工厂是不用钱的。。所以要用好这个特点,下面我们就对上篇文章中的玩具厂进行一次大规模的改造,让其实现工程方法模式!!!!!
是不是很激动,,我也很激动。。。
首先,玩具工厂原址变成指挥站,专门指挥新工厂的建立的,然后指挥站附近新建三个小型工厂:玩具猫工作厂,玩具狗工作厂,玩具熊猫工作厂。各自的工作坊只会做各自的玩具。指挥战中有玩具的生产计划书,每个小型工厂都需要按照指挥部的工作计划书来做玩具(当然计划书只要求了一部分特色功能,各个厂的小玩具到底怎么做,,还要自己做的)。好了,就这么简单,全新的工厂开发模式出来了,这样做的好处是什么呢?我们看一下如果新提供鳄鱼玩具到底该做什么:
1.新建一个小型工厂(鳄鱼工厂)
2.去问指挥部那一份制作计划书,让鳄鱼有计划书中的基本功能(这样才能通过考核然后上线出售)
2.鳄鱼工厂自己购买鳄鱼的制作指南去制作鳄鱼玩具。
现在是不是发现,如果给程序干这事,简直就是,,,超级简单,不会扰乱其他工厂的生产秩序。当有客户来买玩具的时候,他们到指挥站说:我要一只小狗,指挥站说:给钱后请到哪里哪里拿(小狗工厂),然后客户走过去拿就是了。
工厂方法模式的实现
工厂方法模式之所以可以解决简单工厂的模式,是因为它的实现把具体产品的创建推迟到子类中,此时工厂类不再负责所有产品的创建,而只是给出具体工厂必须实现的接口,这样工厂方法模式就可以允许系统不修改工厂类逻辑的情况下来添加新产品,这样也就克服了简单工厂模式中缺点。下面看下工厂模式的具体实现代码(这里还是以简单工厂模式中点菜的例子来实现):
namespace 设计模式之工厂方法模式
{ /// <summary> /// 菜抽象类 /// </summary> public abstract class food { // 输出点了什么菜 public abstract void print(); } /// <summary> /// 西红柿炒鸡蛋这道菜 /// </summary> public class tomatoscrambledeggs : food { public override void print() { console.writeline("西红柿炒蛋好了!"); } } /// <summary> /// 土豆肉丝这道菜 /// </summary> public class shreddedporkwithpotatoes : food { public override void print() { console.writeline("土豆肉丝好了"); } } /// <summary> /// 抽象工厂类 /// </summary> public abstract class creator { // 工厂方法 public abstract food createfoddfactory(); } /// <summary> /// 西红柿炒蛋工厂类 /// </summary> public class tomatoscrambledeggsfactory:creator { /// <summary> /// 负责创建西红柿炒蛋这道菜 /// </summary> /// <returns></returns> public override food createfoddfactory() { return new tomatoscrambledeggs(); } } /// <summary> /// 土豆肉丝工厂类 /// </summary> public class shreddedporkwithpotatoesfactory:creator { /// <summary> /// 负责创建土豆肉丝这道菜 /// </summary> /// <returns></returns> public override food createfoddfactory() { return new shreddedporkwithpotatoes(); } } /// <summary> /// 客户端调用 /// </summary> class client { static void main(string[] args) { // 初始化做菜的两个工厂() creator shreddedporkwithpotatoesfactory = new shreddedporkwithpotatoesfactory(); creator tomatoscrambledeggsfactory = new tomatoscrambledeggsfactory(); // 开始做西红柿炒蛋 food tomatoscrambleeggs = tomatoscrambledeggsfactory.createfoddfactory(); tomatoscrambleeggs.print(); //开始做土豆肉丝 food shreddedporkwithpotatoes = shreddedporkwithpotatoesfactory.createfoddfactory(); shreddedporkwithpotatoes.print(); console.read(); } } }
使用工厂方法实现的系统,如果系统需要添加新产品时,我们可以利用多态性来完成系统的扩展,对于抽象工厂类和具体工厂中的代码都不需要做任何改动。例如,我们我们还想点一个“肉末茄子”,此时我们只需要定义一个肉末茄子具体工厂类和肉末茄子类就可以。而不用像简单工厂模式中那样去修改工厂类中的实现(具体指添加case语句)。具体代码为:
/// <summary> /// 肉末茄子这道菜 /// </summary> public class mincedmeateggplant : food { /// <summary> /// 重写抽象类中的方法 /// </summary> public override void print() { console.writeline("肉末茄子好了"); } } /// <summary> /// 肉末茄子工厂类,负责创建肉末茄子这道菜 /// </summary> public class mincedmeateggplantfactory : creator { /// <summary> /// 负责创建肉末茄子这道菜 /// </summary> /// <returns></returns> public override food createfoddfactory() { return new mincedmeateggplant(); } } /// <summary> /// 客户端调用 /// </summary> class client { static void main(string[] args) { // 如果客户又想点肉末茄子了 // 再另外初始化一个肉末茄子工厂 creator mincemeateggplantfactor = new mincedmeateggplantfactory(); // 利用肉末茄子工厂来创建肉末茄子这道菜 food mincemeateggplant = mincemeateggplantfactor.createfoddfactory(); mincemeateggplant.print(); console.read(); } }
工厂方法模式的uml图
讲解完工厂模式的具体实现之后,让我们看下工厂模式中各类之间的uml图:
从uml图可以看出,在工厂方法模式中,工厂类与具体产品类具有平行的等级结构,它们之间是一一对应的。针对uml图的解释如下:
creator类:充当抽象工厂角色,任何具体工厂都必须继承该抽象类
tomatoscrambledeggsfactory和shreddedporkwithpotatoesfactory类:充当具体工厂角色,用来创建具体产品
food类:充当抽象产品角色,具体产品的抽象类。任何具体产品都应该继承该类
tomatoscrambledeggs和shreddedporkwithpotatoes类:充当具体产品角色,实现抽象产品类对定义的抽象方法,由具体工厂类创建,它们之间有一一对应的关系。
.net中实现了工厂方法的类
.net 类库中也有很多实现了工厂方法的类,例如asp.net中,处理程序对象是具体用来处理请求,当我们请求一个*.aspx的文件时,此时会映射到system.web.ui.pagehandlerfactory类上进行处理,而对*.ashx的请求将映射到system.web.ui.simplehandlerfactory类中(这两个类都是继承于ihttphandlerfactory接口的),关于这点说明我们可以在“c:\windows\microsoft.net\framework\v4.0.30319\config\web.config”文件中找到相关定义,具体定义如下:
<httphandlers> <add path="*.axd" verb="*" type="system.web.httpnotfoundhandler" validate="true" /> <add path="*.aspx" verb="*" type="system.web.ui.pagehandlerfactory" validate="true" /> <add path="*.ashx" verb="*" type="system.web.ui.simplehandlerfactory" validate="true" /> </httphandlers>
下面我们就具体看下工厂方法模式在asp.net中是如何实现的,如果对一个index.aspx页面发出请求时,将会调用pagehandlerfactory中gethandler方法来创建一个index.aspx对象,它们之间的类图关系如下:
总结
工厂方法模式通过面向对象编程中的多态性来将对象的创建延迟到具体工厂中,从而解决了简单工厂模式中存在的问题,也很好地符合了开放封闭原则(即对扩展开发,对修改封闭)。