――OO、Refactoring and Design Pattern
本节目的:
1. 学习使用Abstract Factory模式。
2. 学习使用Factory Method模式。
3. 使用重构手法。
客户: “你们前期的工作很不错,我们非常满意。”
项目经理:“谢谢你们的肯定。”
客户: “不过打印的功能我想下个版本应该做好了吧?”
项目经理:“你们的打印是不是要支持屏幕打印和纸张打印两种模式?”
客户: “Very Good!我就想这样做,你刚才不提醒我,我可能还忘了呢。”
项目经理:“好的,下个版本我们会实现这个功能的。”
等客户走后,项目经理的脸沉了下来:“狡猾狡猾的,先表扬了一下,我看就没有好心肠,这不,活又来了。”然后径直向程序员走去。
客户就是上帝,这点我们不容怀疑。
最苦的还是程序员,这点我们也不容怀疑。
先来分析一下,这里有两种打印方式:POS机屏幕打印,纸张打印,理所当然要建一个抽象类,然后建两个子类。
为了方便,我们这里只打印累计点数和金额。
在main函数中加入以下代码:
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
CPrint类代码如下:
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](/Images/OutliningIndicators/None.gif)
CScreenPrint类代码如下:
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
CPaperPrint类代码如下:
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
编译通过,测试用例通过。
程序运行的很好,没有新的需求,我们就让它这样吧,何必自寻烦恼呢?
然而天下哪有这么好的事呢,过不了多久,客户就开始抱怨了:“我有两个分店,我想每个分店的打印格式不同。”
不可否认,这确实是一个合理的要求,那就做吧,开始重构,使新功能更容易加入。
首先进行改名,UML图如下:
修改CScreenPrintShop1::Print函数为:
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](/Images/OutliningIndicators/None.gif)
修改CPaperPrintShop1::Print函数为:
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](/Images/OutliningIndicators/None.gif)
当然main函数中也要做相应地改动。
编译通过,测试用例通过。
现在可以增加shop 2了,UML图如下:
代码我就不再贴了,和shop1差不多。把出现调用CPaperPrintShop1、CScreenPrintShop1的地方都修改为Shop2,编译通过,测试用例通过。
马上有朋友会问了,这不是一个很明确的Factory Method设计模式吗?是的,这是Factory Method设计模式的应用,但我们只有在一处调用,何必麻烦去写Factory类呢?毕竟使用一些模式会增加好多的代码。
记住一点:不一定用上设计模式才是完美的,实用才是硬道理。
但正如你所说,随着需求的变化,程序中有两处或两处以上用到了打印的功能,那我们就必须修改了。UML图如下:
不慌写代码,这里我们还能分析一下,Screen Print和Paper Print都会用到,为何我们不合并一下呢?UML图如下:
这是一个什么模式啊?其实这是Abstract Factory的简化版。
现在在一开始就初始化打印:
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
然后在调用的地方写如下代码:
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
开始写代码吧,用在写代码的时间其实是比较少的,大多数的时间都是在设计和调试上,而调试的时间又占了大部分,我们要增加编程的效率,缩短调试的时间是最有效的,而建立测试用例就是一个很有效的方法。
使用C++语言编写,在VC++ 6.0环境调试通过。
代码下载
参考资料:
《Refactoring: Improving the Design of Existing Code》 ――Martin Fowler
《Design Patterns - Elements of Reusable Object-Oriented Software》 ――GoF