之前讲到了C++设计模式——工厂方法模式,我们可能会想到,后期产品会越来越多了,建立的工厂也会越来越多,工厂进行了增长,工厂变的凌乱而难于管理;而且由于工厂方法模式创建的对象都是继承于Product的,所以工厂方法模式中,每个工厂只能创建同一产品族的产品,当需要生产一种全新的产品(不继承自Product)时,发现工厂方法是心有余而力不足。
因此抽象工厂模式应运而生
UML类图:
现在要讲的抽象工厂模式,就是工厂方法模式的扩展和延伸,但是抽象工厂模式,更有一般性和代表性;它具有工厂方法具有的优点,也增加了解决实际问题的能力。
抽象工厂模式的通用源码类图:
注意类图上的圈圈、框框相对应,两个抽象的产品类可以有关系,例如共同继承或实现一个抽象类或接口。
#include <iostream>
using namespace std;
// Product A
class ProductA
{
public:
virtual void Show() = 0;
};
class ProductA1 : public ProductA
{
public:
void Show()
{
cout<<"I'm ProductA1"<<endl;
}
};
class ProductA2 : public ProductA
{
public:
void Show()
{
cout<<"I'm ProductA2"<<endl;
}
};
// Product B
class ProductB
{
public:
virtual void Show() = 0;
};
class ProductB1 : public ProductB
{
public:
void Show()
{
cout<<"I'm ProductB1"<<endl;
}
};
class ProductB2 : public ProductB
{
public:
void Show()
{
cout<<"I'm ProductB2"<<endl;
}
};
// Factory
class Factory
{
public:
virtual ProductA *CreateProductA() = 0;
virtual ProductB *CreateProductB() = 0;
};
class Factory1 : public Factory
{
public:
ProductA *CreateProductA()
{
return new ProductA1();
}
ProductB *CreateProductB()
{
return new ProductB1();
}
};
class Factory2 : public Factory
{
ProductA *CreateProductA()
{
return new ProductA2();
}
ProductB *CreateProductB()
{
return new ProductB2();
}
};
int main(int argc, char *argv[])
{
Factory *factoryObj1 = new Factory1();
ProductA *productObjA1 = factoryObj1->CreateProductA();
ProductB *productObjB1 = factoryObj1->CreateProductB();
productObjA1->Show();
productObjB1->Show();
Factory *factoryObj2 = new Factory2();
ProductA *productObjA2 = factoryObj2->CreateProductA();
ProductB *productObjB2 = factoryObj2->CreateProductB();
productObjA2->Show();
productObjB2->Show();
if (factoryObj1 != NULL)
{
delete factoryObj1;
factoryObj1 = NULL;
}
if (productObjA1 != NULL)
{
delete productObjA1;
productObjA1= NULL;
}
if (productObjB1 != NULL)
{
delete productObjB1;
productObjB1 = NULL;
}
if (factoryObj2 != NULL)
{
delete factoryObj2;
factoryObj2 = NULL;
}
if (productObjA2 != NULL)
{
delete productObjA2;
productObjA2 = NULL;
}
if (productObjB2 != NULL)
{
delete productObjB2;
productObjB2 = NULL;
}
}
有N个产品族,在抽象工厂类中就应该有N个创建方法,比如有A、B,两个产品族,就要创建两个方法用于创建A、B两个产品族的对象,至于具体创建的是产品族中哪一个产品的对象,则结合业务情况进行分析,比如A产品族有A1、A2 两个产品,B产品族有B1、B2两个产品,抽象工厂类中的两个方法分别是创建A产品族对象和B产品族对象的,创建A产品族对象的方法到底是创建A1还是A2,创建B产品族对象的方法到底是创建B1还是B2,这是要结合实际业务情况进行分析的。
有M条生产线就应该实现M个实现工厂类,在每个实现工厂中,实现不同产品族的生产任务。就比如创建A1、B1是一条生产线,创建A2、B2是一条生产线,那就需要两个实现工厂类,第一个实现工厂类中创建A1、B1,第二个实现工厂类中创建A2、B2。
下面通过女娲造人来更加深入地理解抽象工厂模式,具体代码如下:
#include <iostream>
using namespace std;
//多个产品族共同基础Human类
class Human
{
public:
//每个人种都有相应的颜色
virtual void getColor() = 0;
//人类会说话
virtual void talk() = 0;
//每个人都有性别
virtual void getSex() = 0;
};
//这里有3个产品族,分别是黄色人种、白色人种和黑色人种
class YellowHuman : public Human
{
public:
void getColor()
{
cout << "黄种人的颜色是黄色的" << endl;
}
void talk()
{
cout << "黄种人说话一般是双字节" << endl;
}
};
class WhiteHuman :public Human
{
public:
void getColor()
{
cout << "白种人的颜色是白色的" << endl;
}
void talk()
{
cout << "白种人说话一般是单字节" << endl;
}
};
class BlackHuman :public Human
{
public:
void getColor()
{
cout << "黑种人的颜色是黑色的" << endl;
}
void talk()
{
cout << "黑种人说话一般人听不懂" << endl;
}
};
//产品族创建完毕后开始创建具体产品,每个产品族有两个产品
class YellowFemale:public YellowHuman
{
public:
void getSex()
{
cout << "这是一个黄人女性" << endl;
}
};
class YellowMale :public YellowHuman
{
public:
void getSex()
{
cout << "这是一个黄人男性" << endl;
}
};
class WhiteFemale :public WhiteHuman
{
public:
void getSex()
{
cout << "这是一个白人女性" << endl;
}
};
class WhiteMale :public WhiteHuman
{
public:
void getSex()
{
cout << "这是一个白人男性" << endl;
}
};
class BlackFemale :public BlackHuman
{
public:
void getSex()
{
cout << "这是一个黑人女性" << endl;
}
};
class BlackMale :public BlackHuman
{
public:
void getSex()
{
cout << "这是一个黑人男性" << endl;
}
};
//创建一个抽象工厂类
//有3个产品族,因此抽象工厂类需要有3个方法,分别创建不同产品族的某个产品的对象
class HumanFactory
{
public:
//创建一个黄种人
virtual Human* createYellow() = 0;
//创建一个白种人
virtual Human* createWhite() = 0;
//创建一个黑种人
virtual Human* createBlack() = 0;
};
//有两条生产线,创建女人和男人,因此有两个工厂实现类
//创建女人工厂实现类
class FemaleFactory :public HumanFactory
{
public:
Human* createYellow()
{
//创建黄人女性
return new YellowFemale();
}
Human* createWhite()
{
//创建白人女性
return new WhiteFemale();
}
Human* createBlack()
{
//创建黑人女性
return new BlackFemale();
}
};
//创建男人实现工厂类
class MaleFactory :public HumanFactory
{
public:
Human* createYellow()
{
//创建黄人男性
return new YellowMale();
}
Human* createWhite()
{
//创建白人男性
return new WhiteMale();
}
Human* createBlack()
{
//创建黑人男性
return new BlackMale();
}
};
int main()
{
HumanFactory* maleFactory = new MaleFactory();
HumanFactory* femaleFactory = new FemaleFactory();
//工厂建立完毕,开始生产人
//创建一个黄人男性
Human* yellowMale = maleFactory->createYellow();
//创建一个黄人女性
Human* yellowFemale = femaleFactory->createYellow();
yellowMale->getColor();
yellowMale->getSex();
yellowMale->talk();
yellowFemale->talk();
yellowFemale->getColor();
yellowFemale->getSex();
return 0;
if(yellowMale != NULL)
{
delete yellowMale;
yellowMale = NULL;
}
if(yellowFemale != NULL)
{
delete yellowFemale;
yellowFemale = NULL;
}
}
抽象工厂模式的优点:
- 封装性,每个产品的实现类不是高层模块要关心的,它要关心的是什么?是接口,是抽象,它不关心对象是如何创建出来,这由谁负责呢?工厂类,只要知道工厂类是谁,我就能创建出一个需要的对象,省时省力,优秀设计就应该如此。
- 产品族内的约束为非公开状态。例如生产男女比例的问题上,猜想女娲娘娘肯定有自己的打算,不能让女盛男衰,否则女性的优点不就体现不出来了吗?那在抽象工厂模式,就应该有这样的一个约束:每生产1个女性,就同时生产出1.2个男性,这样的生产过程对调用工厂类的高层模块来说是透明的,它不需要知道这个约束,我就是要一个黄色女性产品就可以了,具体的产品族内的约束是在工厂内实现的。
抽象工厂模式的缺点:
抽象工厂模式的最大缺点就是产品族扩展非常困难,为什么这么说呢?我们以最开始的通用代码为例,如果要增加一个产品C,也就是说产品家族由原来的2个增加到3个,看看我们的程序有多大改动吧!抽象类AbstractCreator要增加一个方法createProductC(),然后两个实现类都要修改,想想看,这严重违反了开闭原则,而且我们一直说明抽象类和接口是一个契约。改变契约,所有与契约有关系的代码都要修改,那么这段代码叫什么?叫“有毒代码”,——只要与这段代码有关系,就可能产生侵害的危险!
适用场合:
工厂方法模式适用于产品种类结构单一的场合,为一类产品提供创建的接口;而抽象工厂方法适用于产品种类结构多的场合,主要用于创建一组不同产品族却彼此相关的产品,为它们提供创建的接口;就是当具有多个抽象角色时,抽象工厂便可以派上用场。
参考资料:
- 《设计模式之禅》
- https://www.cnblogs.com/ring1992/p/9592713.html