【设计模式(1):工厂模式】
写在前面——
如果转载请注明出处,谢谢大家支持
——Forward
我的微博——秦京一梦
QQ技术交流群——forTheDream(225117179)
今天,一个同学找我帮他做一个程序(貌似是某公司的面试题哦~@_@),题目如下:
【销售税都是由基本税和进口税构成。基本税是商品价格的10%,书籍,食品和医疗产品免征基本税。如果是进口商品,需要征收商品价格5%的进口税,所有进口商品都要征收进口税。
购买商品时,需要打印一张收据,上面会列出所有购买的商品名称和价格(含税),总价及所交税的金额。销售税的计算公式为:t=税率n%*单价p(注:np/100四舍五入到最接近的0.05)。】
其实题目本身并不难,作为开发人员,或许我们不能仅仅要求功能上的正确,更多的是对代码结构上有更高的要求,比如要求代码清晰易懂,具有更高的复用性和扩展性。设计模式正不正是帮助我们来达到这个目的的吗?!
今天我们就设计模式中比较简单而常用的一种——工厂方法来做一次学习。
工厂模式一般分为工厂方法模式(简单工厂模式视为工厂方法模式的一种)和抽象工厂模式。下面进行一个简单的对比:
工厂方法模式:拥有一个产品抽象类,可以派生出多个具体的产品子类;拥有一个工厂抽象类,可以派生出多个具体的工厂子类;每个具体的工厂子类只创建一个具体的产品子类实例。抽象工厂模式:具有多个产品抽象类,每个抽象产品类可以派生出多个具体产品类;一个抽象工厂类,可以派生出多个具体工厂类;每个具体工厂类可以创建多个具体产品实例。
这样的描述可以还是不够直观,Forward在做整理的时候,看到一篇博客的留言,感觉说的挺贴切的,大家感受一下——
1.简单工厂:工厂可以创建同一系列的产品,产品的接口一致,但工厂就要根据参数进行判断到底创建哪种产品。卖早饭的张婆婆:可以做茶叶蛋,包子,稀饭
2.工厂方法:可以有多种工厂,工厂有共同的接口,一个工厂只能产生一种产品,比起简单工厂,工厂方法就不需要判断,耦合度低了不少。刘老板:只卖包子的包子铺,只卖稀饭的稀饭庄
3.抽象工厂:可以产生多个系列的产品,有2个维度的产品。饮料店老板:可乐系列产品、咖啡系列产品,每种系列产品又分小杯、中杯、大杯
可能我们很快就可以作如下的结构,有一个虚基类ProductBase类,所有商品都继承它,子类自己实现自己的征税额计算方法,然后通过向ProductBaseFactoryBook传递商品ID来创建对应商品,客户端只是通过ProductBaseFactoryBook来创建所需商品(比如写一个switch语句或者if-else来创建对应商品),这样做的好处是在一定程度上达到了对调用者屏蔽具体类的作用。
图 1
但这样的设计还是存在问题的,比如商店的商品越来越多,我们的ProductBaseFactoryBook的CreateProduct接口会越来越臃肿,这肯定不是我们想看到的,看来这样的设计还是有欠妥之处,我们马上对上面的设计做一次修改,如下图所示——
图 2
这里我们设计了一个工厂抽象类ProductBaseFactory和一个产品抽象类ProductBase,针对题目中的书本,派生出两个类——ProductBaseFactoryBook和ProductBook,ProductBaseFactoryBook实现基类的ProductBase接口只负责创建ProductBook实例。这样就是我们上面提到的工厂方法了。
当我们的商店再来新的商品时,我们依样画葫芦,创建对应的工厂A和商品A即可,而工厂A则只负责创建商品A。而调用者每次只需要获取对应工厂的CreateProduct接口就行了。但是这里我们注意到还有一个问题,商品是分进口和非进口的,如果采用这样的设计,同样一种商品进口和非进口还是混淆在一起,不易扩展,再改改我们的设计吧~~
图 3
我们从ProductBase中派生出两个虚基类ProductImport和ProductNotImport然后对应的派生出每种商--品的进口和非进口类型,而我们的ProductBaseFactory则派生出两种类型ProductBaseFactoryImport和ProductBaseFactoryNotImport两种,在Factory类型中我们添加对应商品的创建接口,如CreateProductBook、CreateProductCD等等。这样的设计耦合度又降低了。这种设计恰恰使用了抽象工厂设计模式。
在这篇博客中,我们对设计模式中的工厂模式的几种情况进行了逐一设计实现,对工厂模式也基本有了一个比较清楚的认识。总结一下——
设计模式的使用笼统来说使得代码整体变得更好。而其中的工厂模式的使用则具有如下有点:
1、代码结构更加清晰易懂,利用面向对象编程中的封装、继承和多态特性,对调用者屏蔽了对象创建过程,使得具体的对象创建更加简单,调用者可以将更多的注意力放到对象的实际调用而不用再纠结于对象实例化的繁琐工作中;
2、工厂模式的使用大大降低了代码耦合度,调用者只知道工厂和对象类本身的存在,其中实例化过程涉及的其他类,对调用者来说几乎是透明的。
参考博客:
http://blog.csdn.net/hguisu/article/details/7505909
http://blog.csdn.net/zhengzhb/article/details/7359385
http://blog.csdn.net/zhengzhb/article/details/7348707