文章目录
- C++设计模式 - 创建型模式之工厂模式
- 接口和针对接口编程
- 1. 简单工厂模式
- 适用场合
- UML
- 代码示例
- 2. 工厂方法模式
- 适用场合
- UML
- 代码示例
- 3. 抽象工厂模式
- 适用场合
- UML
- 代码示例
- 总结
C++设计模式 - 创建型模式之工厂模式
工厂模式属于创建型模式,大致可以分为三类,简单工厂模式、工厂方法模式、抽象工厂模式
。听上去差不多,都是工厂模式。
工厂模式的主要作用是封装对象的创建,分离对象的创建和操作过程,用于批量管理对象的创建过程,便于程序的维护和扩展。
接口和针对接口编程
接口从语法层面来说,是纯虚类。从软件设计的意义来说,通常用接口来定义类的外观,约定了实现类应该要实现的功能。封装变化——即隔离变化。从软件的整体结构来看,只要接口不变,内部实现不会影响到外部应用,从而使得系统更灵活,具有更好的扩展性和可维护性。
1. 简单工厂模式
它的主要特点是需要在工厂类中做判断,从而创造相应的产品。当增加新的产品时,就需要修改工厂类。有点抽象,举个例子就明白了。有一家生产处理器核的厂家,它只有一个工厂,能够生产两种型号的处理器核。客户需要什么样的处理器核,一定要显示地告诉生产工厂。
适用场合
在程序中,需要创建的对象很多,导致对象的构建复杂时,需要使用简单工厂模式;
由于对象的创建过程是我们不需要去关心的,而我们注重的是对象的实际操作,所以,我们需要分离对象的创建和操作两部分,如此,方便后期的程序扩展和维护。
UML
代码示例
#include <bits/stdc++.h>
using std::cout;
using std::endl;
//
//简单工厂模式
//
typedef enum PhoneTypeTag {
MI_PHONE,
IPHONE_PHONE,
HUAWEI_PHONE
} PhoneType;
//产品抽象基类 AbstractProduct
class Phone {
//添加虚析构函数!
public:
virtual void type() = 0;//代表共有属性
};
//
//具体的产品类
//
class MiPhone : public Phone {
public:
void type() override {
cout << "I'm XiaoMi Phone !" << endl;
}
};
class IPhone : public Phone {
public:
void type() override {
cout << "I'm IPhone !" << endl;
}
};
class HuaweiPhone : public Phone {
public:
void type() override {
cout << "I'm Huawei Phone !" << endl;
}
};
//工厂类 手机代工厂
class PhoneFactory {
public:
//根据产品信息创建具体的产品类示例,返回一个抽象产品类
std::shared_ptr<Phone> MakePhone(const PhoneType type) {
switch (type) {
case PhoneType::MI_PHONE:
return std::make_shared<MiPhone>();
case PhoneType::IPHONE_PHONE:
return std::make_shared<IPhone>();
case PhoneType::HUAWEI_PHONE:
return std::make_shared<HuaweiPhone>();
default:
return nullptr;
}
}
};
int main() {
PhoneFactory phoneFactory;
std::shared_ptr<Phone> m_phone = nullptr;
m_phone = phoneFactory.MakePhone(PhoneType::MI_PHONE);
m_phone->type();
m_phone = phoneFactory.MakePhone(PhoneType::IPHONE_PHONE);
m_phone->type();
m_phone = phoneFactory.MakePhone(PhoneType::HUAWEI_PHONE);
m_phone->type();
//动态绑定
//m_phone = std::make_shared<MiPhone>();
//m_phone->type();
return 0;
}
代码运行输出结果如下:
I'm XiaoMi Phone !
I'm IPhone !
I'm Huawei Phone !
- 主要特点:产品创建过程在工厂类中完成,当增加新产品时,需要修改工厂类。使用简单工厂模式,我们只需要知道具体的产品型号就可以创建一个产品。
- 缺点:工厂类集中了所有产品类的创建逻辑,如果产品量较大,会使得工厂类变的非常臃肿。
2. 工厂方法模式
-
其实这才是正宗的工厂模式,简单工厂模式只是一个简单的对创建过程封装。
-
和简单工厂模式中工厂负责生产所有产品相比,工厂方法模式将生成具体产品的任务分发给具体的产品工厂。
在代码实现上,工厂方法模式在简单工厂模式的基础上增加对工厂的基类抽象,不同的产品创建采用不同的工厂创建(从工厂的抽象基类派生),这样创建不同的产品过程就由不同的工厂分工解决:FactoryA专心负责生产ProductA,FactoryB专心负责生产ProductB,FactoryA和FactoryB之间没有关系;如果到了后期,如果需要生产ProductC时,我们则可以创建一个FactoryC工厂类,该类专心负责生产ProductC类产品。
适用场合
工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅提供具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。
UML
代码示例
#include <bits/stdc++.h>
using std::cout;
using std::endl;
//
//工厂方法模式
//
//产品抽象基类 AbstractProduct
class Phone {
//添加虚析构函数!
public:
virtual void type() = 0;//代表共有属性
};
//
//具体的产品类
//
class MiPhone : public Phone {
public:
void type() override {
cout << "I'm XiaoMi Phone !" << endl;
}
};
class IPhone : public Phone {
public:
void type() override {
cout << "I'm IPhone !" << endl;
}
};
class HuaweiPhone : public Phone {
public:
void type() override {
cout << "I'm Huawei Phone !" << endl;
}
};
//抽象工厂类,提供一个创建接口
class PhoneFactory {
public:
//提供创建产品实例的接口,返回抽象产品类
virtual std::shared_ptr<Phone> MakePhone() = 0;
};
//具体的创建工厂类,使用抽象工厂类提供的接口,各具体的工厂去创建具体的产品实例
class MiPhoneFactory : public PhoneFactory {
public:
std::shared_ptr<Phone> MakePhone() override {
return std::make_shared<MiPhone>();
}
};
class IPhoneFactory : public PhoneFactory {
public:
std::shared_ptr<Phone> MakePhone() override {
return std::make_shared<IPhone>();
}
};
class HuaWeiPhoneFactory : public PhoneFactory {
public:
std::shared_ptr<Phone> MakePhone() override {
return std::make_shared<HuaweiPhone>();
}
};
int main() {
std::shared_ptr<Phone> m_pPhone = nullptr;
m_pPhone = MiPhoneFactory().MakePhone();
m_pPhone->type();
m_pPhone = IPhoneFactory().MakePhone();
m_pPhone->type();
m_pPhone = HuaWeiPhoneFactory().MakePhone();
m_pPhone->type();
return 0;
}
- 该模式相对于简单工厂模式的优势在于:便于后期产品种类的扩展。如果需要增加新的产品类,只需要扩展一个相应的工厂类即可。
- 缺点:产品类数据较多时,需要实现大量的工厂类,这无疑增加了代码量。
工厂方法减轻了工厂类的负担,新增一种“手机”只需添加一个特定的“手机工厂”即可,这就符合了开放闭合原则:
3. 抽象工厂模式
-
工厂方法自然比简单工厂更加灵活,但当业务有所变更时,比如需要添加“手机”的周边产品——“电脑”呢?这时候我们就需要一个更复杂的模式——抽象工厂
-
抽象工厂是一个产品簇的概念,一个工厂可以生产多种业务相关的产品。我们在工厂方法的基础上扩充一下代码:定义一个抽象工厂接口
AbstractFactory
,通过不同的方法生产出一个“抽象”产品簇(Phone和PC)。回过头来再看工厂方法,事实上它就是抽象工厂最简单的一种场景设计——只生成一种产品。 -
抽象工厂模式通过在AbstarctFactory中增加创建产品的接口,并在具体子工厂中实现新加产品的创建,当然前提是子工厂支持生产该产品。否则继承的这个接口可以什么也不干。
适用场合
工厂方法模式适用于产品种类结构单一的场合,为一类产品提供接口;
而抽象工厂方法适用于产品种类结构多的场合,主要用于创建一组(有多个种类)相关的产品,为它们提供创建的接口。
UML
代码示例
#include <bits/stdc++.h>
using std::cout;
using std::endl;
//
//抽象工厂模式
//
//手机产品抽象基类 AbstractProduct
class Phone {
//添加虚析构函数!
public:
virtual void type() = 0;//代表共有属性
};
//
//具体的手机产品类
//
class MiPhone : public Phone {
public:
void type() override {
cout << "I'm XiaoMi Phone !" << endl;
}
};
class IPhone : public Phone {
public:
void type() override {
cout << "I'm IPhone !" << endl;
}
};
class HuaweiPhone : public Phone {
public:
void type() override {
cout << "I'm Huawei Phone !" << endl;
}
};
//PC产品抽象基类 AbstractProduct
class PC {
//添加虚析构函数!
public:
virtual void type() = 0;//代表共有属性
};
//
//具体的手机产品类
//
class MiPC : public PC {
public:
void type() override {
cout << "I'm XiaoMi PC !" << endl;
}
};
class MACPC : public PC {
public:
void type() override {
cout << "I'm MAC PC !" << endl;
}
};
class HuaweiPC : public PC {
public:
void type() override {
cout << "I'm Huawei PC !" << endl;
}
};
//抽象工厂类,提供一个创建接口,其中增加PC产品接口
class AbstractFactory {
public:
//提供创建产品实例的接口,返回抽象产品类
virtual std::shared_ptr<Phone> MakePhone() = 0;
virtual std::shared_ptr<PC> MakePC() = 0;
};
//具体的创建工厂类,使用抽象工厂类提供的接口,各具体的工厂去创建具体的产品实例
class MiFactory : public AbstractFactory {
public:
std::shared_ptr<Phone> MakePhone() override {
return std::make_shared<MiPhone>();
}
std::shared_ptr<PC> MakePC() override{
return std::make_shared<MiPC>();
}
};
class IPhoneFactory : public AbstractFactory {
public:
std::shared_ptr<Phone> MakePhone() override {
return std::make_shared<IPhone>();
}
std::shared_ptr<PC> MakePC() override{
return std::make_shared<MACPC>();
}
};
class HuaWeiFactory : public AbstractFactory {
public:
std::shared_ptr<Phone> MakePhone() override {
return std::make_shared<HuaweiPhone>();
}
std::shared_ptr<PC> MakePC() override{
return std::make_shared<HuaweiPC>();
}
};
//另外一个代工厂,生产MiPhone和MAC
class OdmFactory : public AbstractFactory {
public:
std::shared_ptr<Phone> MakePhone() override {
return std::make_shared<MiPhone>();
}
std::shared_ptr<PC> MakePC() override{
return std::make_shared<MACPC>();
}
};
int main()
{
std::shared_ptr<Phone> m_pPhone = nullptr;
std::shared_ptr<PC> m_pPC = nullptr;
MiFactory miFactory;
IPhoneFactory iPhoneFactory;
HuaWeiFactory huaWeiFactory;
OdmFactory odmFactory;
m_pPhone = miFactory.MakePhone();
m_pPC = miFactory.MakePC();
m_pPhone->type();
m_pPC->type();
m_pPhone = iPhoneFactory.MakePhone();
m_pPC = iPhoneFactory.MakePC();
m_pPhone->type();
m_pPC->type();
m_pPhone = huaWeiFactory.MakePhone();
m_pPC = huaWeiFactory.MakePC();
m_pPhone->type();
m_pPC->type();
m_pPhone = odmFactory.MakePhone();
m_pPC = odmFactory.MakePC();
m_pPhone->type();
m_pPC->type();
return 0;
}
代码输出如下:
I'm XiaoMi Phone !
I'm XiaoMi PC !
I'm IPhone !
I'm MAC PC !
I'm Huawei Phone !
I'm Huawei PC !
I'm XiaoMi Phone !
I'm MAC PC !
在抽象工厂模式中,增加新的产品族很方便(如可以将IPhone和HuaWeiPC作为一个产品系列,只用增加一个工厂即可),但是增加新的产品等级结构很麻烦(如,增加键盘作为新的产品,那么不仅需要增加新的产品类,同时各个工厂也需要进行对应的调整,将键盘这一产品增加进去)。
总结
工厂模式最直观的理解是,减少new创建对象的方式,用接口的方式来返回一个对象,而new创建的方式被封装了
-
简单工厂:调用者只需使用单例工厂就可获取同一范畴的所有产品
-
工厂方法:调用者并不知道它在运行时会获取何种产品,只知道某个特定的工厂能生成出满足需求的产品
-
抽象工厂:调用者可以在运行时从特定的工厂中获得所有信息相关的产品簇(可以对产品进行组合)
工厂方法模式和抽象工厂模式区别:区别在于产品,如果产品单一,最合适用工厂模式,但是如果有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。再通俗深化理解下:工厂模式针对的是一个产品等级结构,抽象工厂模式针对的是面向多个产品等级结构的。
是否可以这样理解呢:工厂方法模式生产一种产品,抽象工厂模式生产一系列产品,构成的是一个生态