假如要处理两类数据:男和女(男女考虑问题是不一样的)
最简单的就是定义两个类( Male和Female)(V1.0)
/*V1.0*/
class Male{
}
class Female{
}
但是我们发现Male和Female是有共同部分的,所以这时候我们有定义 了Human类,让Male和Female继承Human类(V2.0),这时候改动比较大。目前来说有三个类。
/*V2.0*/
class Human{
}
class Male:public Human{
}
class Female:public Human{
}
然后我们有发现实际上还要考虑肤色,这时候有几种考虑:
1.改Human类,添加有关肤色的内容,但是肤色凭什么比性别的层次高呢?
2.改Male类和Female类,给其中添加与肤色有关的内容,这是肯定有大量代码冗余啊!
3.推倒重来---疯了!
......
其实到这里我们已经会发现路已经走不下去了,随着项目的进行,需要修改的地方越来越多,最终可能导致崩溃!
而且在演进的过程中我们希望添加大于改动,上述的内容希望继承前面的代码,其结果却是越来越乱!
如下改动:
1.肤色有关的内容放到Human类中
2.Male和Female改为 BlackMale,BlackFemale,WhiteMale,WhiteFemale,YellowMale和YellowFemale
至此有7个类,如果还有其他的在添加(类的急剧膨胀!)(V3.0)
/*V3.0*/
class Human{
}
class YellowMale:public Human{
}
class YellowFemale:public Human{
}
class BlackMale:public Human{
}
class BlackFemale:public Human{
}
class WhiteMale:public Human{
}
class WhiteFemale:public Human{
}
不过在演进到V3.0的时候,有几个问题:
- V1.0,V2.0的知识都不能用了
- 类太多,使用者也不容易记忆
能有种方法减少记忆吗?
有!就是归类!将代码也归类!
使用者只要调用极少的函数,就可以使用对应的类创建对象,所以这时候要做两件事:
1.提供创建对象的统一工具
2.定义使用类统一的界面
考虑创建对象的工具,如下:
/*工厂模式V1.0*/
class Factory{
...
YellowMale *createYellowMale();
YellowFemale *createYellowFemale();
...
}
也可以如下改进,使用带参函数:
/*工厂模式v2.0*/
class Factory{
...
Human *createHuman(string name){
switch(name){
case "YellowMale":
...
casse "YellowFemale":
...
}
}
}
这些都是工厂模式!工厂模式就是为了提供创建对象的统一工具!
能不能再改进一下呢?如果在添加棕色人种呢?这是怎么办呢?
仔细分析一下上述代码,我们发现这六个函数是相关的(这个很关键,如果没有这一点的话我们只能去修改代码了),可以进行归类,或者按照肤色分,或者按照性别分都可以,此处按照肤色分:
/*抽象工厂v1.0*/
class YellowFactory{
...
YellowMale *createYellowMale();
YellowFemale *createYellowFemale();
...
}
class BlackFactory{
...
BlackMale *createBlackMale();
BlackFemale *createBlackFemale();
...
}
class WhiteFactory{
...
WhiteMale *createWhiteMale();
WhiteFemale *createWhiteFemale();
...
}
但是太丑陋了!
- 3个类的有太多的冗余代码,且记忆的内容太多
- 类与类之间是有联系的,不能视而不见
- 如果现在再添加一类人种,比如说棕色呢?
将公共的代码抽取出来,形成这三个类的父类,而父类作为接口:
/*抽象工厂v2.0*/
class Factory{
...
virtual Male *createMale()=0;
virtual Female *createFemale()=0;
...
}
class YellowFactory :public Factory{
...
YellowMale *createMale();
YellowFemale *createFemale();
...
}
class BlackFactory:public Factory{
...
BlackMale *createMale();
BlackFemale *createFemale();
...
}
class WhiteFactory:public Factory{
...
WhiteMale *createMale();
WhiteFemale *ceateFemale();
...
}
*请注意抽象工厂V2.0中的Factory类,在设计之初并不知道真正的工厂创建的对象类型,但是知道有那些动作,而下面的具体工厂是知道创建对象的类型的(比如说YellowFactory类是知道要创建的对象类型的)。
另外这种形式扩展也容易,比如要添加棕色人种,那么只要添加棕色人种类和棕色人种工厂即可:
class BrownMale:public Human{
}
class BrownFeMale:public Human{
}
class BrownFactory:public Factory{
...
BrownMale *createMale();
BrownFemale *createFemale();
...
}
也许有人会说抽象工厂V2.0版的工厂有4个类,就改成1个类或2个类,不是类更少,更好记吗?比如:
/*1个类实现方案1*/
class Factory{
...
YellowMale *createYellowMale();
YellowMale *createYellowFemale();
...
BlackMale *createBlackMale();
BlackFemale *createBlackFemale();
...
WhiteMale *createWhiteMale();
WhiteFemale *createWhiteFemale();
...
}
/*1个类实现方案2*/
class Factory{
...
Human *createHuman(string name){
switch(name){
case "YellowMale":
...
casse "YellowFemale":
...
}
}
}
这实际上前面的工厂模式了,而且如果要有新的类(如BrownMale和BrownFemale)它还要修改!
或是2个类实现:
/*2个类实现*/
class AbstractFactory{
virtual Male *createMale(string )=0;
virtual Female *createFemale(string )=0;
}
class ConcreteFactory:public AbstructFactory{
...
Male *createMale(string name){
switch(name){
case "YellowMale":
...
casse "YellowFemale":
...
}
}
Female *createFemale(string name){
...
}
...
}
2个类的方案在扩展时主要靠修改!(又是它!) ,记住宁添勿改! 且在使用时也是非常不便的:
...
ConcreteFactory fac= new ConcreteFactory();
YellowMale *p1=(YellowMale *)fac->createMale("YellowMale");
...
*本文中采用4个类实现抽象工厂模式,<<设计之禅>>中采用3个类:
class HumanFactory{
...
Human *createYellowHuman();
Human *createWhiteHuman();
Human *createBlackHuman();
...
}
class MaleFactory:public HumanFactory{
...
YellowMaleHuman *createYellowHuman();
WhiteMaleHuman *createWhiteHuman();
BlackMaleHuman *createBlackHuman();
...
}
class FemaleFactory:public HumanFactory{
...
YellowFemaleHuman *createYellowHuman();
WhiteFemaleHuman *createWhiteHuman();
BlackFemaleHuman *createBlackHuman();
...
}
似乎本文的方法扩展性更好些,这只是合并、分类的标准不同而已。