C++设计模式之工厂模式(创建型模式)
学习软件设计,向OO高手迈进!
设计模式(Design pattern)是软件开发人员在软件开发过程中面临的一般问题的解决方案。
这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
是前辈大神们留下的软件设计的"招式"或是"套路"。
什么是工厂模式
对于工厂模式,具体上可以分为三类:
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
简单工厂模式
简单工厂模式是最简单的设计模式之一,其实它并不属于GOF的23种设计模式,但应用也十分频繁,同时也是其余创建型模式的基础,因此有必要先学习简单工厂模式。
简单工厂基本实现流程
- 设计一个抽象产品类,它包含一些公共方法的声明
- 从抽象产品类中派生出多个具体产品类,具体产品类中实现具体产品生产的相关代码
- 设计一个工厂类,工厂类提供一个生产各种产品的方法,该方法根据传入参数(产品名称)创建不同的具体产品类对象
- 客户端只需调用工厂类的这个方法,并传入具体产品参数,即可得到一个具体产品对象
定义
定义一个简单工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类
简单工厂模式结构
从简单工厂模式的定义可以看出,在简单工厂模式中,大体上有3个角色:
- 工厂角色(Creator):这是简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象
- 抽象产品角色(AbstractProduct):这是简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。该类可以是接口,也可以是抽象类
- 具体产品角色(ConcreteProduct):抽象产品的派生类,包含具体产品特有的实现方法,是简单工厂模式的创建目标
UML类图
其UML类图如下
Version 1.0
下面我们使用手机生产来讲解该模式:
一、定义抽象产品类AbstractProduct
Phone类:手机类(AbstractProduct)
class Phone {
public:
virtual void make(void) = 0;
};
二、定义具体产品类
MiPhone类:小米手机类(Product1)
class MiPhone : public Phone {
public:
MiPhone() {
this->make();
}
virtual void make(void) {
cout << "make xiaomi phone!" << endl;
}
};
IPhone类:苹果手机类(Product2)
class IPhone : public Phone {
public:
IPhone() {
this->make();
}
virtual void make(void) {
cout << "make iphone!" << endl;
}
};
三、定义工厂类和工厂方法
SimpleFactory类:手机生产工厂类(Factory)
class SimpleFactory {
public:
static Phone* makePhone(const string& phoneType) {
if (phoneType == "MiPhone") {
return new MiPhone();
} else if (phoneType == "iPhone") {
return new IPhone();
}
return nullptr;
}
};
四、客户端
int main(int argc, char** argv) {
// make xiaomi phone!
Phone* miPhone = SimpleFactory::makePhone("MiPhone");
// make iphone
Phone* iPhone = SimpleFactory::makePhone("iPhone");
return 0;
}
执行结果
make xiaomi phone!
make iphone!
Version 1.1
扩展增加生产华为手机实现
一、扩展具体产品类
Huawei类:华为手机类(Product3)
class HuaweiPhone : public Phone {
public:
HuaweiPhone() {
this->make();
}
virtual void make(void) {
cout << "make huawei phone!" << endl;
}
};
二、扩展工厂类方法
SimpleFactory类:手机生产工厂类(Factory)
class SimpleFactory {
public:
static Phone* makePhone(const string& phoneType) {
if (phoneType == "MiPhone") {
return new MiPhone();
} else if (phoneType == "iPhone") {
return new IPhone();
} else if (phoneType == "HuaweiPhone") {
return new HuaweiPhone();
}
return nullptr;
}
};
三、扩展客户端
int main(int argc, char** argv) {
// make xiaomi phone!
Phone* miPhone = SimpleFactory::makePhone("MiPhone");
// make iphone
Phone* iPhone = SimpleFactory::makePhone("iPhone");
// make huawei phone
Phone* huaweiphone = SimpleFactory::makePhone("HuaweiPhone");
return 0;
}
执行结果
make xiaomi phone!
make iphone!
make huawei phone!
在简单工厂模式中,工厂类是整个模式的关键所在。它包含了必要的判断逻辑,能够根据外界给定的条件去判断应该创建哪个具体类的实例。用户在使用时可以直接根据工厂类去创建所需的实例,而无需关心这些对象是如何组织并创建的,从这一点上来说,这有利于整个软件体系结构的优化。但是,简单工厂模式的缺点也正体现在工厂类上,由于工厂类中集中了所有实例的创建逻辑,当我们增加了一个新的
具体类时,需要同时修改工厂类(多加一个if),这违反了“开闭原则”。
优点
- 工厂类提供创建具体产品的方法,并包含一定判断逻辑,客户不必参与产品的创建过程。
- 客户只需要知道对应产品的参数即可,参数一般简单好记,如数字、字符或者字符串等。
缺点
- 扩展性差(实例中想增加一种手机产品,除了新增一个手机产品类,还需要修改工厂类方法)。
- 不同的产品需要不同额外参数的时候 不支持。
适用场合
- 在程序中,需要创建的对象很多,导致对象的new操作多且杂时,需要使用简单工厂模式。
- 由于对象的创建过程是我们不需要去关心的,而我们注重的是对象的实际操作,所以,我们需要分离对象的创建和操作两部分,如此,方便后期的程序扩展和维护。
工厂方法模式(Factory Method)
定义
定义一个用于创建对象的接口,但是让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。
简单工厂模式中,每新增一个具体产品,就需要修改工厂类内部的判断逻辑。为了不修改工厂类,遵循开闭原则,工厂方法模式中不再使用工厂类统一创建所有的具体产品,而是针对不同的产品设计了不同的工厂,每一个工厂只生产特定的产品。
工厂方法模式结构
从工厂方法模式简介中,可以知道该模式有以下几种角色:
- 抽象工厂(AbstractFactory):所有生产具体产品的工厂类的基类,提供工厂类的公共方法
- 具体工厂(ConcreteFactory):生产具体产品的工厂
- 抽象产品(AbstractProduct):所有产品的基类,提供产品类的公共方法
- 具体产品(ConcreteProduct):具体的产品类
UML类图
Version 2.0
接下来继续使用生产手机的例子来讲解该模式:
一、定义抽象产品类AbstractProduct
Phone类:手机类(AbstractProduct)
class Phone {
public:
virtual void make(void) = 0;
};
二、定义具体产品类
MiPhone类:小米手机类(Product1)
class MiPhone : public Phone {
public:
MiPhone() {
this->make();
}
virtual void make(void) {
cout << "make xiaomi phone!" << endl;
}
};
IPhone类:苹果手机类(Product2)
class IPhone : public Phone {
public:
IPhone() {
this->make();
}
virtual void make(void) {
cout << "make iphone!" << endl;
}
};
三、定义抽象工厂类AbstractFactory
AbstractFactory类:生产不同产品的工厂的抽象类
class AbstractFactory {
public:
virtual Phone* makePhone(void) = 0;
};
四、定义具体工厂类
XiaoMiFactory类:生产小米手机的工厂类(ConcreteFactory1)
class XiaoMiFactory : public AbstractFactory {
public:
virtual Phone* makePhone(void) {
return new MiPhone();
}
};
AppleFactory类:生产苹果手机的工厂类(ConcreteFactory2)
class AppleFactory : public AbstractFactory {
public:
virtual Phone* makePhone(void) {
return new IPhone();
}
};
五、客户端
int main(int argc, char** argv) {
AbstractFactory* miFactory = new XiaoMiFactory();
AbstractFactory* appleFactory = new AppleFactory();
Phone* miPhone = miFactory->makePhone();
Phone* iPhone = appleFactory->makePhone();
return 0;
}
执行结果
make xiaomi phone!
make iphone!
Version 2.1
扩展增加生产华为手机实现
一、扩展具体产品类
Huawei类:华为手机类(Product3)
class HuaweiPhone : public Phone{
public:
HuaweiPhone() {
this->make();
}
virtual void make(void) {
cout << "make huawei phone!" << endl;
}
};
二、扩展具体工厂类
HuaweiFactory类:生产华为手机的工厂类(ConcreteFactory3)
class HuaweiFactory : public AbstractFactory {
public:
virtual Phone* makePhone(void) {
return new HuaweiPhone();
}
};
三、扩展客户端
int main(int argc, char** argv) {
AbstractFactory* miFactory = new XiaoMiFactory();
AbstractFactory* appleFactory = new AppleFactory();
AbstractFactory* huaweiFactory = new HuaweiFactory();
Phone* miPhone = miFactory->makePhone();
Phone* iPhone = appleFactory->makePhone();
Phone* huaweiphone = huaweiFactory->makePhone();
return 0;
}
执行结果
make xiaomi phone!
make iphone!
make huawei phone!
优点
- 工厂方法用于创建客户所需产品,同时向客户隐藏某个具体产品类将被实例化的细节,用户只需关心所需产品对应的工厂。
- 工厂自主决定创建何种产品,并且创建过程封装在具体工厂对象内部,多态性设计是工厂方法模式的关键。
- 新加入产品时,无需修改原有代码,增强了系统的可扩展性,符合开闭原则。
缺点
- 添加新产品时需要同时添加新的产品工厂,系统中类的数量成对增加,增加了系统的复杂度,更多的类需要编译和运行,增加了系统的额外开销。
适用场合
- 客户端不需要知道它所需要创建的对象的类。
- 抽象工厂类通过其子类来指定创建哪个对象。
抽象工厂模式(Abstract Factory)
定义
提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。
简言之,一个工厂可以提供创建多种相关产品的接口,而无需像工厂方法一样,为每一个产品都提供一个具体工厂。
抽象工厂模式结构
抽象工厂模式结构与工厂方法模式结构类似,不同之处在于,一个具体工厂可以生产多种同类相关的产品:
- 抽象工厂(AbstractFactory):所有生产具体产品的工厂类的基类,提供工厂类的公共方法
- 具体工厂(ConcreteFactory):生产具体产品的工厂
- 抽象产品(AbstractProduct):所有产品的基类,提供产品类的公共方法
- 具体产品(ConcreteProduct):具体的产品类
UML类图
Version 3.0
一、定义A类抽象产品类AbstractProductA
Phone类:定义手机产品的接口(AbstractPhone)
class Phone {
public:
virtual void make(void) = 0;
};
二、定义具体A类产品类
MiPhone类:小米手机类(Product1)
class MiPhone : public Phone {
public:
MiPhone() {
this->make();
}
virtual void make(void) {
cout << "make xiaomi phone!" << endl;
}
};
IPhone类:苹果手机类(Product2)
class IPhone : public Phone {
public:
IPhone() {
this->make();
}
virtual void make(void) {
cout << "make iphone!" << endl;
}
};
三、定义B类抽象产品类 AbstractProductB
PC类:定义PC产品的接口(AbstractPC)
class PC {
public:
virtual void make(void) = 0;
};
四、定义具体B类产品类
小米PC类:定义小米电脑产品(MIPC)
class MiPC : public PC {
public:
MiPC() {
this->make();
}
virtual void make(void) {
cout << "make xiaomi PC!" << endl;
}
};
MAC类:定义苹果电脑产品(MAC)
class MAC : public PC {
public:
MAC() {
this->make();
}
virtual void make(void) {
cout << "make MAC!" << endl;
}
};
五、定义抽象工厂AbstractFactory
AbstractFactory类
class AbstractFactory {
public:
virtual Phone* makePhone(void) = 0;
virtual PC* makePC(void) = 0;
};
六、定义具体工厂ConcreteProduct
XiaoMiFactory类:小米工厂类(ConcreteFactory1)
class XiaoMiFactory : public AbstractFactory {
public:
virtual Phone* makePhone(void) {
return new MiPhone();
}
virtual PC* makePC(void) {
return new MiPC();
}
};
AppleFactory类:苹果工厂类(ConcreteFactory2)
class AppleFactory : public AbstractFactory {
public:
virtual Phone* makePhone(void) {
return new IPhone();
}
virtual PC* makePC(void) {
return new MAC();
}
};
七、客户端
int main(int argc, char** argv) {
AbstractFactory* miFactory = new XiaoMiFactory();
AbstractFactory* appleFactory = new AppleFactory();
Phone* miPhone = miFactory->makePhone();
PC* miPC = miFactory->makePC();
Phone* iPhone = appleFactory->makePhone();
PC* Mac = appleFactory->makePC();
return 0;
}
执行结果
make xiaomi phone!
make xiaomi PC!
make iphone!
make MAC!
优点
- 抽象工厂方法用于创建客户所需产品,同时向客户隐藏某个具体产品类将被实例化的细节,用户只需关心所需产品对应的工厂。
- 新加入产品系列时,无需修改原有系统,增强了系统的可扩展性,符合开闭原则。
缺点
- 在已有产品系列中添加新产品时需要修改抽象层代码,对原有系统改动较大,违背开闭原则。
适用场合
- 一系列/家族产品需要被同时使用时,适合使用抽象工厂模式。
- 产品结构稳定,设计完成之后不会向系统中新增或剔除某个产品。