1.工厂方法模式简介
在之前的文章设计模式之简单工厂模式中我们支持了简单工厂模式存在的最大问题是违背了“开放封闭原则”,每次增加新的产品时,都需要修改工厂类的逻辑。为了解决这种模式的不足,同时能充分利用简单工厂模式的优点,本文将会介绍工厂方法模式。
在简单工厂模式中,每次新增一个具体的产品,都需要修改工厂类中的判断逻辑。为了不修改工厂类,遵循开放封闭的原则。工厂方法模式中不再使用工厂类来统一创建所有的具体产品,而是针对不同的产品设计不同的工厂,每个工厂负责只生产特定的产品。
工厂方法模式定义:定义一个用于创建对象的接口,但是让子类决定将哪个类实例化,工厂方法模式让一个类的实例化延迟到了子类。
2.工厂方法模式结构
工厂方法模式中主要涉及以下几种概念:
抽象工厂(AbstractFactory):所有生产具体产品的工厂类的基类,提供工厂类的公共方法。
具体工厂(ConcreteFactory):生产具体的产品
抽象产品(AbstractProduct):所有产品的基类,提供产品类的公共方法
具体产品(ConcreteProduct):具体产品的类
3.工厂方法模式实战
假设有如下一个场景:CurrCoder想进行户外运动,它可以选择打篮球、踢足球、打排球。如果他想要哪个球,他只需要到篮球保管室、足球保管室、排球保管室取对应的球即可。
#include <iostream> using namespace std; // 抽象产品类AbstractSportProduct class AbstractSportProduct{ public: AbstractSportProduct(){} // 抽象方法 void printName(){}; void play(){}; }; // 具体产品类 class Basketball: public AbstractSportProduct { public: Basketball(){ printName(); play(); } // 具体的实现方法 void printName(){ cout << "CurryCoder get Basketball\n"; } void play(){ cout << "CurryCoder play Basketball\n"; } }; class Football: public AbstractSportProduct { public: Football(){ printName(); play(); } // 具体的实现方法 void printName(){ cout << "CurryCoder get Football\n"; } void play(){ cout << "CurryCoder play Football\n"; } }; class Volleyball: public AbstractSportProduct { public: Volleyball(){ printName(); play(); } // 具体的实现方法 void printName(){ cout << "CurryCoder get Volleyball\n"; } void play(){ cout << "CurryCoder play Volleyball\n"; } }; // 抽象工厂类 class AbstractFactory{ public: virtual AbstractSportProduct* getSportProduct() = 0; }; // 具体工厂类 class BasketballFactory: public AbstractFactory{ public: BasketballFactory(){ cout << "Basketball Factory\n"; } AbstractSportProduct* getSportProduct() { cout << "Basketball\n"; return new Basketball(); } }; class FootballFactory: public AbstractFactory{ public: FootballFactory(){ cout << "Football Factory\n"; } AbstractSportProduct* getSportProduct() { cout << "Football\n"; return new Football(); } }; class VolleyballFactory: public AbstractFactory{ public: VolleyballFactory(){ cout << "Volleyball Factory\n"; } AbstractSportProduct* getSportProduct() { cout << "Volleyball\n"; return new Volleyball(); } }; // 客户端 int main(){ cout << "==========工厂方法模式===========\n"; // 定义工厂类对象和产品类对象 AbstractFactory* fac = nullptr; AbstractSportProduct* product = nullptr; fac = new BasketballFactory(); product = fac->getSportProduct(); cout << "==========我是分隔线=========\n"; fac = new FootballFactory(); product = fac->getSportProduct(); cout << "==========我是分隔线=========\n"; fac = new VolleyballFactory(); product = fac->getSportProduct(); return 0; };
实战的最终结果,如下图所示:
4.工厂方法模式总结
如果CurryCoder想打羽毛球(Badminton),只需要增加一个羽毛球工厂(BadmintonFactory),然后在客户端的代码中修改具体工厂类的类名,而原有的代码无需修改。因此,相对于简单工厂模式,工厂方法模式更符合开放封闭原则。
优点:
(1).工厂方法用于创建客户所需的产品,同时向客户隐藏某个具体产品类将被实例化的细节,用户只关心所需产品所对应的工厂。
(2).工厂自行决定创建何种产品,并且创建过程封装在具体工厂对象内部,多态性设计是工厂方法模式的关键;
(3).新加入产品时,无需改变原有代码,增加了系统的可扩展性,符合开放封闭原则。
缺点:
(1).添加新产品时需要同时添加新产品对应的产品工厂,系统中类的数量会成对增加,增加了系统的复杂度。更多的类需要编译和运行,增加了系统额外的开销。
(2).工厂和产品都引入了抽象层,客户端中的代码均使用的是抽象层(AbstractFactory和AbstractSportProduct),这增加了系统的抽象层次和理解难度。