目录
工厂模式是设计模式中最常用的创建型模式之一,它解决了直接使用new
关键字创建对象时带来的诸多问题。本文将通过对比直接new
的方式,详细讲解工厂模式的三种形式 ------ 简单工厂、工厂方法和抽象工厂,并通过生活实例和代码示例帮助新手理解它们的优势和应用场景。
一、为什么不用new,而需要工厂模式?
在初学C++的时候,我们都是直接使用new关键字来定义对象的,例如:
cpp
Pizza* pizza = new CheesePizza();
这种方式看似简单,但在实际开发中会带来一系列问题:
(1)耦合度过高:创建一个对象必须要完整的知道对象的名字,当需要更换类型时,所有用new的地方都要重新修改成别的类。
(2)违反开闭原则:当添加新类型的时候,需要修改所有创建对象的代码
(3)如果创建对象后还需要进行一系列初始化工作,会让业务代码多出很多初始化工作,代码逻辑冗杂,违反单一职能原则。
工厂模式的核心思想是:将对象的创建与使用分离。由专门的 工厂类来负责对象的创建,从而解决上述问题。
类比我们生活中的例子:你想要购买一辆汽车,你不需要手动new,然后对汽车做一系列的设置才能使用。如果你去4s店购买,所有的设置他都帮你完成了,你拿到手的就是可以直接使用的汽车。工厂模式就是专业的事情交给专业的类去做,达到职能解耦的效果。
二、简单工厂
简单工厂模式由一个工厂类根据传入的参数,决定创建哪一种产品类的实例。它不属于 GoF 的 23 种设计模式,但在实际开发中应用广泛,是工厂模式的基础形式。
假设你经营一家水果店,顾客想要什么水果你都直接给他。
简单工厂模式就好像一个小作坊,只要产品是一个品类的都能做,使用的时候只需要告诉小作坊你要该类下面的什么产品即可。
cpp
//简单工厂
class Fruit
{
public:
Fruit() {}
virtual void show() = 0;
};
class Apple :public Fruit
{
void show()override
{
std::cout << "我是一个苹果" << std::endl;
}
};
class Banana:public Fruit
{
public:
void show()override
{
std::cout << "我是一个香蕉" << std::endl;
}
};
class FruitFactory
{
public:
std::shared_ptr<Fruit> CreateFruit(const std::string & name)
{
if (name=="苹果")
{
return std::make_shared<Apple>();
}
else
{
return std::make_shared<Banana>();
}
}
};
int main()
{
//创建工厂类
FruitFactory ff;
std::shared_ptr<Fruit> fruit=ff.CreateFruit("苹果");
fruit->show();
fruit = ff.CreateFruit("香蕉");
fruit->show();
return 0;
}
简单工厂模式实现较为简单,便于理解工厂模式的原理。但是他严重违反了开闭原则,当想要新增水果品类的时候,需要修改工厂类。
三、工厂模式
正是因为简单工厂违反了开闭原则,工厂模式则是把产品和工厂绑定起来,一个工厂只负责生产一种产品,当需要新增新的产品的时候,直接扩展工厂即可。
⼯⼚⽅法模式: 在简单⼯⼚模式下新增多个⼯⼚,多个产品,每个产品对应⼀个⼯⼚。假设现在有A、B 两种产品,则开两个⼯⼚,⼯⼚ A 负责⽣产产品 A,⼯⼚ B 负责⽣产产品 B,⽤⼾只知道产品的⼯⼚名,⽽不知道具体的产品信息,⼯⼚不需要再接收客⼾的产品类别,⽽只负责⽣产产品。
cpp
//工厂模式
class Fruit
{
public:
Fruit() {}
virtual void show() = 0;
};
class Apple :public Fruit
{
void show()override
{
std::cout << "我是一个苹果" << std::endl;
}
};
class Banana:public Fruit
{
public:
void show()override
{
std::cout << "我是一个香蕉" << std::endl;
}
};
class FruitFactory
{
public:
virtual std::shared_ptr<Fruit> CreateFruit() = 0;
};
class AppleFactory:public FruitFactory
{
public:
std::shared_ptr<Fruit> CreateFruit()
{
return std::make_shared<Apple>();
}
};
class BananaFactory :public FruitFactory
{
public:
std::shared_ptr<Fruit> CreateFruit()
{
return std::make_shared<Banana>();
}
};
int main()
{
//创建苹果工厂
std::shared_ptr<FruitFactory> appleff(new AppleFactory());
std::shared_ptr<Fruit> apple = appleff->CreateFruit();
apple->show();
//创建香蕉工厂
std::shared_ptr<FruitFactory> bananaff(new BananaFactory());
std::shared_ptr<Fruit> banana = bananaff->CreateFruit();
banana->show();
return 0;
}
工厂模式虽然符合了开闭原则,方便后续扩展。但是当产品类很多的时候,这会使得系统中类的个数成倍增加,在⼀定程度上增加了系统的耦合度。
四、抽象工厂
抽象⼯⼚模式: ⼯⼚⽅法模式通过引⼊⼯⼚等级结构,解决了简单⼯⼚模式中⼯⼚类职责太重的问题,但由于⼯⼚⽅法模式中的每个⼯⼚只⽣产⼀类产品,可能会导致系统中存在⼤量的⼯⼚类,势必会增加系统的开销。此时,我们可以考虑将⼀些相关的产品组成⼀个产品族(位于不同产品等级结构中功能相关联的产品组成的家族),由同⼀个⼯⼚来统⼀⽣产,这就是抽象⼯⼚模式的基本思想。
简单来说,抽象工厂是用来生产一系列配套产品的设计模式。在之前的工厂模式中,每一个产品都对应一个工厂类,一系列产品容易拿混。而简单工厂不利于扩展新系列产品。抽象工厂模式本质是对简单工厂的抽象,当每个系列产品的数量种类都一致的时候,扩展新系列比较方便。不过一旦想要在每个系列中插入新产品,则严重违反了开闭原则,因为他本质是简单工厂。
cpp
#include <iostream>
#include <memory>
#include <string>
using namespace std;
// 抽象产品1:水果(产品类别1)
class Fruit {
public:
virtual ~Fruit() = default;
virtual void show() = 0; // 展示水果信息(含产地,体现产品族)
};
// 具体产品1-1:北方苹果(属于"北方产品族")
class NorthApple : public Fruit {
public:
void show() override {
cout << "我是北方农场的苹果" << endl;
}
};
// 具体产品1-2:南方香蕉(属于"南方产品族")
class SouthBanana : public Fruit {
public:
void show() override {
cout << "我是南方农场的香蕉" << endl;
}
};
// 抽象产品2:动物(产品类别2)
class Animal {
public:
virtual ~Animal() = default;
virtual void voice() = 0; // 展示动物叫声(含产地,体现产品族)
};
// 具体产品2-1:北方羊(属于"北方产品族")
class NorthSheep : public Animal {
public:
void voice() override {
cout << "北方农场的羊:咩咩咩" << endl;
}
};
// 具体产品2-2:南方狗(属于"南方产品族")
class SouthDog : public Animal {
public:
void voice() override {
cout << "南方农场的狗:汪汪汪" << endl;
}
};
// 抽象工厂:定义"产品族"的创建接口(必须覆盖所有产品类别)
class FarmFactory {
public:
virtual ~FarmFactory() = default;
virtual shared_ptr<Fruit> createFruit() = 0; // 创建本产品族的水果
virtual shared_ptr<Animal> createAnimal() = 0; // 创建本产品族的动物
};
// 具体工厂1:北方农场工厂(创建"北方产品族"的所有产品)
class NorthFarmFactory : public FarmFactory {
public:
shared_ptr<Fruit> createFruit() override {
return make_shared<NorthApple>(); // 北方产品族的水果:北方苹果
}
shared_ptr<Animal> createAnimal() override {
return make_shared<NorthSheep>(); // 北方产品族的动物:北方羊
}
};
// 具体工厂2:南方农场工厂(创建"南方产品族"的所有产品)
class SouthFarmFactory : public FarmFactory {
public:
shared_ptr<Fruit> createFruit() override {
return make_shared<SouthBanana>(); // 南方产品族的水果:南方香蕉
}
shared_ptr<Animal> createAnimal() override {
return make_shared<SouthDog>(); // 南方产品族的动物:南方狗
}
};
// 工厂生产者(可选,用于简化工厂创建,本质是简单工厂)
class FactoryProducer {
public:
static shared_ptr<FarmFactory> getFarmFactory(const string& farmType) {
if (farmType == "北方农场") {
return make_shared<NorthFarmFactory>();
} else if (farmType == "南方农场") {
return make_shared<SouthFarmFactory>();
}
return nullptr;
}
};
int main() {
// 1. 获取"北方农场工厂"(对应"北方产品族")
shared_ptr<FarmFactory> northFarm = FactoryProducer::getFarmFactory("北方农场");
shared_ptr<Fruit> northFruit = northFarm->createFruit();
shared_ptr<Animal> northAnimal = northFarm->createAnimal();
northFruit->show(); // 输出:我是北方农场的苹果
northAnimal->voice(); // 输出:北方农场的羊:咩咩咩
// 2. 获取"南方农场工厂"(对应"南方产品族")
shared_ptr<FarmFactory> southFarm = FactoryProducer::getFarmFactory("南方农场");
shared_ptr<Fruit> southFruit = southFarm->createFruit();
shared_ptr<Animal> southAnimal = southFarm->createAnimal();
southFruit->show(); // 输出:我是南方农场的香蕉
southAnimal->voice(); // 输出:南方农场的狗:汪汪汪
return 0;
}
抽象⼯⼚模式适⽤于⽣产多个⼯⼚一系列产品衍⽣的设计模式,增加新的产品会很复杂,需要对原有系统进⾏较⼤的修改,甚⾄需要修改抽象层代码,违背了"开闭原则"。