一、工厂方法模式
之前的简单工厂模式的最大问题:违背“开闭”原则,每当增加新的产品时,需要修改工厂类的逻辑。工厂方法模式不再使用工厂类统一创建所有的具体产品,而是让每个工厂只生产特定的产品。即让一个类的实例化延迟到其子类。
1.1 工厂方法模式的角色
抽象工厂(AbstractFactory):所有生产具体产品的工厂类的基类,提供工厂类的公共方法;
具体工厂(ConcreteFactory):生产具体的产品
抽象产品(AbstractProduct):所有产品的基类,提供产品类的公共方法
具体产品(ConcreteProduct):具体的产品类
1.2 UML类图
场景:客户Jungle想拿篮球就去篮球保管室,而不是像简单工厂模式,直接去一个保管所有体育器材的体育保管室:
如果对UML类图关系和符号忘了的童鞋可以复习下 【设计模式】UML类图关系与符号,大概就是:
类的继承是用空心三角和实线,空心三角指向父类,如下面的具体的篮球工厂类BasketballFactory继承基类(抽象工厂类)AbstractFactory;再比如具体的篮球产品类Basketball继承基类(对应的篮球工厂类``)
二、代码实现
2.1 抽象产品类
定义抽象产品类AbstractSportProduct,方法不提供实现。
//抽象产品类AbstractProduct class AbstractSportProduct{ public: AbstractSportProduct(){} //抽象方法: void printName(){}; void play(){}; };
2.2 三个具体产品类
//三个具体产品类 //具体产品类Basketball class Basketball :public AbstractSportProduct{ public: Basketball(){ printName(); play(); } //具体实现方法 void printName(){ printf("Jungle get Basketball\n"); } void play(){ printf("Jungle play Basketball\n\n"); } }; //具体产品类Football class Football :public AbstractSportProduct{ public: Football(){ printName(); play(); } //具体实现方法 void printName(){ printf("Jungle get Football\n"); } void play(){ printf("Jungle play Football\n\n"); } }; //具体产品类Volleyball class Volleyball :public AbstractSportProduct{ public: Volleyball(){ printName(); play(); } //具体实现方法 void printName(){ printf("Jungle get Volleyball\n"); } void play(){ printf("Jungle play Volleyball\n\n"); } };
2.3 定义抽象工厂类
定义抽象工厂类AbstractFactory
,其中的getSportProduct()
方法为纯虚方法。
//抽象工厂类 class AbstractFactory{ public: //纯虚函数 virtual AbstractSportProduct *getSportProduct() = 0; };
2.4 三个具体工厂
//定义三个具体工厂类 //具体工厂类BasketballFactory class BasketballFactory :public AbstractFactory{ public: BasketballFactory(){ printf("BasketballFactory\n"); } AbstractSportProduct *getSportProduct(){ printf("basketball"); return new Basketball(); } }; //具体工厂类FootballFactory class FootballFactory :public AbstractFactory{ public: //构造函数 FootballFactory(){ printf("FootballFactory\n"); } AbstractSportProduct *getSportProduct(){ return new Football(); } }; //具体工厂类VolleyballFactory class VolleyballFactory :public AbstractFactory{ public: //构造函数 VolleyballFactory(){ printf("VolleyballFactory\n"); } //抽象产品类,返回一个棒球对象的产品指针 AbstractSportProduct *getSportProduct(){ return new Volleyball(); } };
2.5 客户端代码
首先定义工厂类对象和产品类对象指针;
用该父类指针(抽象工厂类指针)指向子类对象(如篮球工厂对象),并且利用该指针调用getSportProduct(),该函数在父类中被定义为纯虚函数,并且在各自的子类(具体工厂子类)中进行实现。
#include <iostream> #include "FactoryMethod.h" int main(){ printf("工厂方法模式\n"); //定义工厂类对象和产品类对象 AbstractFactory *fac = NULL; AbstractSportProduct *product = NULL; fac = new BasketballFactory(); product = fac->getSportProduct(); fac = new FootballFactory(); product = fac->getSportProduct(); fac = new VolleyballFactory(); product = fac->getSportProduct(); system("pause"); return 0; }
三、工厂方法模式小结
- 如果某客户想玩棒球,只需要增加一个棒球工厂
BaseballFactory
,然后在客户端代码中修改具体工厂类的类名,而原有的类的代码无需修改。 - 和简单工厂模式相比,工厂方法模式更加符合开闭原则,也是使用频率最高的设计模式之一。