抽象工厂模式
(Abstract Factory)
抽象工厂 是一种创建型设计模式,它能创建一系列相关的对象,而无需指定其具体类。
1. 问题
假设你正在开发一款家具商店模拟器。你的代码中包括一些类,用于表示:
1. 一系列相关产品, 例如 椅子 Chair 、 沙发 Sofa 和咖啡桌 CoffeeTable 。
2. 系列产品的不同变体。 例如, 你可以使用 现代 Modern 、维多利亚 Victorian 、 装饰风艺术 ArtDeco 等风格生成 椅子 、 沙发 和 咖啡桌 。
系列产品及其不同变体。
你需要设法单独生成每件家具对象,这样才能确保其风格一致。如果顾客收到的家具风格不一样,他们可不会开心。
此外, 你也不希望在添加新产品或新风格时修改已有代码。家具供应商对于产品目录的更新非常频繁,你不会想在每次更新时都去修改核心代码的。
2. 解决方案
首先,抽象工厂模式建议为系列中的每件产品明确声明接口(例如椅子、沙发或咖啡桌)。然后,确保所有产品变体都继承这些接口。例如,所有风格的椅子都实现 椅子 接口;所有风格的咖啡桌都实现 咖啡桌 接口,以此类推。
接下来,我们需要声明抽象工厂——包含系列中所有产品构造方法的接口。例如 createChair 创建椅子 、 createSofa创建沙发 和 createCoffeeTable 创建咖啡桌 。 这些方法必须返回抽象产品类型,即我们之前抽取的那些接口: 椅子 , 沙发 和 咖啡桌 等等。
同一对象的所有变体都必须放置在同一个类层次结构之中。
那么该如何处理产品变体呢?对于系列产品的每个变体,我们都将基于 抽象工厂 接 口创建不同的工厂类。每个工厂类都只能返回特定类别的产品,例如, 现代家具工厂 ModernFurnitureFactory 只能创建 现代椅子 ModernChair 、 现代沙发 ModernSofa 和现代咖啡桌 ModernCoffeeTable 对象。
客户端代码可以通过相应的抽象接口调用工厂和产品类。你无需修改实际客户端代码,就能更改传递给客户端的工厂类,也能更改客户端代码接收的产品变体。
每个具体工厂类都对应一个特定的产品变体。
假设客户端想要工厂创建一把椅子。客户端无需了解工厂类,也不用管工厂类创建出的椅子类型。无论是现代风格,还是维多利亚风格的椅子,对于客户端来说没有分别,它只需调用抽象 椅子 接口就可以了。这样一来,客户端只需知道椅子以某种方式实现了 sitOn 坐下 方法就足够了。此外,无论工厂返回的是何种椅子变体,它都会和由同一工厂对象创建的沙发或咖啡桌风格一致。
最后一点说明:如果客户端仅接触抽象接口,那么谁来创建实际的工厂对象呢?一般情况下,应用程序会在初始化阶段创建具体工厂对象。而在此之前,应用程序必须根据配置文件或环境设定选择工厂类别。
3. 结构
抽象工厂模式的结构
其中:
* Abstract Factory声明一个创建抽象产品对象的操作接口。
* Concrete Factory实现创建具体产品对象的操作。
* Abstract Product为一类产品对象声明一个接口。
* Concrete Product定义一个将被相应的具体工厂创建的产品对象, 实现Abstract Product 接口。
* Client仅使用由Abstract Factory和Abstract Product类声明的接口。
4. 实现方式
1. 以不同的产品类型与产品变体为维度绘制矩阵。
2. 为所有产品声明抽象产品接口。
然后让所有具体产品类实现这些接口。
3. 声明抽象工厂接口,并且在接口中为所有抽象产品提供一组构建方法。
4. 为每种产品变体实现一个具体工厂类。
5. 在应用程序中开发初始化代码。
该代码根据应用程序配置或当前环境,对特定具体工厂类进行初始化。然后将该工厂对象传递给所有需要创建产品的类。
6. 找出代码中所有对产品构造函数的直接调用,将其替换为对工厂对象中相应构建方法的调用。
5. 代码示例
abstract_factory.h
#ifndef DESIGN_PATTERNS_ABSTRACT_FACTORY_H
#define DESIGN_PATTERNS_ABSTRACT_FACTORY_H
//------------------------------//
class User{};
//------------------------------//
class Chair //"凳子"类
{
public:
virtual void hasLegs(int) = 0;
virtual void confortLevel(User*) = 0;
};
class ArtDeco_Chair :public Chair //"艺术风凳子"类
{
public:
void hasLegs(int);
void confortLevel(User*);
};
class Victorian_Chair :public Chair //"维多利亚风凳子"类
{
public:
void hasLegs(int);
void confortLevel(User*);
};
class Modern_Chair :public Chair //"时尚风凳子"类
{
public:
void hasLegs(int);
void confortLevel(User*);
};
//------------------------------//
class Sofa //"沙发"类
{
public:
virtual void sofaSize(int) = 0;
virtual void confortLevel(User*) = 0;
};
class ArtDeco_Sofa :public Sofa //"艺术风沙发"类
{
public:
virtual void sofaSize(int);
virtual void confortLevel(User*);
};
class Victorian_Sofa :public Sofa //"维多利亚风沙发"类
{
public:
virtual void sofaSize(int);
virtual void confortLevel(User*);
};
class Modern_Sofa :public Sofa //"时尚风沙发"类
{
public:
virtual void sofaSize(int);
virtual void confortLevel(User*);
};
//------------------------------//
class CoffeeTable //"桌子"类
{
public:
virtual void tableLength(int) = 0;
virtual void confortLevel(User*) = 0;
};
class ArtDeco_CoffeeTable :public CoffeeTable //"艺术风桌子"类
{
public:
void tableLength(int);
void confortLevel(User*);
};
class Victorian_CoffeeTable :public CoffeeTable //"维多利亚风桌子"类
{
public:
void tableLength(int);
void confortLevel(User*);
};
class Modern_CoffeeTable :public CoffeeTable //"时尚风桌子"类
{
public:
void tableLength(int);
void confortLevel(User*);
};
//------------------------------//
class IFactory //"抽象工厂"类
{
public:
virtual Chair* createChair() = 0;//创建凳子
virtual Sofa* createSofa() = 0;//创建沙发
virtual CoffeeTable* createTable() = 0;//创建桌子
};
class ArtDecoFactory :public IFactory //"艺术风工厂"类
{
public:
Chair* createChair();
Sofa* createSofa();
CoffeeTable* createTable();
};
class VictorianFactory :public IFactory //"维多利亚风工厂"类
{
public:
Chair* createChair();
Sofa* createSofa();
CoffeeTable* createTable();
};
class ModernFactory :public IFactory //"时尚风工厂"类
{
public:
Chair* createChair();
Sofa* createSofa();
CoffeeTable* createTable();
};
//------------------------------//
#endif //DESIGN_PATTERNS_ABSTRACT_FACTORY_H
abstract_factory.c
#include <iostream>
#include "abstract_factory.h"
using namespace std;
//------------------------------//
void ArtDeco_Chair::hasLegs(int x)
{
cout << "艺术风凳子==凳腿数" << x << endl;
}
void ArtDeco_Chair::confortLevel(User* user)
{
cout << "艺术风凳子=舒适度" << endl;
}
void Victorian_Chair::hasLegs(int x)
{
cout << "维多利亚风凳子==凳腿数" << x << endl;
}
void Victorian_Chair::confortLevel(User* user)
{
cout << "维多利亚风凳子=舒适度" << endl;
}
void Modern_Chair::hasLegs(int x)
{
cout << "时尚风凳子==凳腿数" << x << endl;
}
void Modern_Chair::confortLevel(User* user)
{
cout << "时尚风凳子=舒适度" << endl;
}
//------------------------------//
void ArtDeco_Sofa::sofaSize(int a)
{
cout << "艺术风沙发==沙发尺寸" << a << endl;
}
void ArtDeco_Sofa::confortLevel(User* user)
{
cout << "艺术风沙发=舒适度" << endl;
}
void Victorian_Sofa::sofaSize(int a)
{
cout << "维多利亚风沙发==沙发尺寸" << a << endl;
}
void Victorian_Sofa::confortLevel(User* user)
{
cout << "维多利亚风沙发=舒适度" << endl;
}
void Modern_Sofa::sofaSize(int a)
{
cout << "时尚风沙发==沙发尺寸" << a << endl;
}
void Modern_Sofa::confortLevel(User* user)
{
cout << "时尚风沙发=舒适度" << endl;
}
//------------------------------//
void ArtDeco_CoffeeTable::tableLength(int a)
{
cout << "艺术风桌子==桌子腿" << a << endl;
}
void ArtDeco_CoffeeTable::confortLevel(User* user)
{
cout << "艺术风桌子=舒适度" << endl;
}
void Victorian_CoffeeTable::tableLength(int a)
{
cout << "维多利亚风桌子==桌子腿" << a << endl;
}
void Victorian_CoffeeTable::confortLevel(User* user)
{
cout << "维多利亚风桌子=舒适度" << endl;
}
void Modern_CoffeeTable::tableLength(int a)
{
cout << "时尚风桌子==桌子腿" << a << endl;
}
void Modern_CoffeeTable::confortLevel(User* user)
{
cout << "时尚风桌子=舒适度" << endl;
}
//------------------------------//
Chair* ArtDecoFactory::createChair()
{
Chair* chair = new ArtDeco_Chair();
return chair;
}
Sofa* ArtDecoFactory::createSofa()
{
Sofa* sofa = new ArtDeco_Sofa();
return sofa;
}
CoffeeTable* ArtDecoFactory::createTable()
{
CoffeeTable* table = new ArtDeco_CoffeeTable();
return table;
}
Chair* VictorianFactory::createChair()
{
Chair* chair = new Victorian_Chair();
return chair;
}
Sofa* VictorianFactory::createSofa()
{
Sofa* sofa = new Victorian_Sofa();
return sofa;
}
CoffeeTable* VictorianFactory::createTable()
{
CoffeeTable* table = new Victorian_CoffeeTable();
return table;
}
Chair* ModernFactory::createChair()
{
Chair* chair = new Modern_Chair();
return chair;
}
Sofa* ModernFactory::createSofa()
{
Sofa* sofa = new Modern_Sofa();
return sofa;
}
CoffeeTable* ModernFactory::createTable()
{
CoffeeTable* table = new Modern_CoffeeTable();
return table;
}
//------------------------------//
Main.c
//------------------------------//
#include <iostream>
#include "abstract_factory.h"
using namespace std;
//------------------------------//
// Created by Cls on 2024/03/28.
//------------------------------//
int main(int argc, char *argv[])
{
IFactory* i_factory;
Chair* i_chair;
Sofa* i_sofa;
CoffeeTable* i_table;
//-----------------//
i_factory = new VictorianFactory();
i_chair = i_factory->createChair();
i_chair->hasLegs(3);
i_chair->confortLevel(new User());
i_sofa = i_factory->createSofa();
i_sofa->sofaSize(10);
i_sofa->confortLevel(new User());
i_table = i_factory->createTable();
i_table->tableLength(4);
i_table->confortLevel(new User());
cout << "------------------" << endl;
//-----------------//
//-----------------//
i_factory = new ArtDecoFactory();
i_chair = i_factory->createChair();
i_chair->hasLegs(4);
i_chair->confortLevel(new User());
i_sofa = i_factory->createSofa();
i_sofa->sofaSize(20);
i_sofa->confortLevel(new User());
i_table = i_factory->createTable();
i_table->tableLength(8);
i_table->confortLevel(new User());
cout << "------------------" << endl;
//-----------------//
delete i_factory;
delete i_chair;
delete i_sofa;
delete i_table;
//-----------------//
return 0;
}
//------------------------------//
打印输出
6. 应用场景
如果代码需要与多个不同系列的相关产品交互,但是由于无法提前获取相关信息,或者出于对未来扩展性的考虑,你不希望代码基于产品的具体类进行构建,在这种情况下,你可以使用抽象工厂。
抽象工厂为你提供了一个接口,可用于创建每个系列产品的对象。只要代码通过该接口创建对象,那么你就不会生成与应用程序已生成的产品类型不一致的产品。
如果你有一个基于一组抽象方法的类,且其主要功能因此变得不明确,那么在这种情况下可以考虑使用抽象工厂模式。
在设计良好的程序中,每个类仅负责一件事。如果一个类与多种类型产品交互,就可以考虑将工厂方法抽取到独立的工厂类或具备完整功能的抽象工厂类中。
7. 优缺点
√ 你可以确保同一工厂生成的产品相互匹配。
√ 你可以避免客户端和具体产品代码的耦合。
√ 单一职责原则。你可以将产品生成代码抽取到同一位置,使得代码易于维护。
√ 开闭原则。向应用程序中引入新产品变体时,你无需修改客户端代码。
× 由于采用该模式需要向应用中引入众多接口和类,代码可能会比之前更加复杂。
8. 与其他模式的关系
• 在许多设计工作的初期都会使用工厂方法(较为简单,而且可以更方便地通过子类进行定制),随后演化为使用抽象工厂、原型或生成器(更灵活但更加复杂)。
• 生成器重点关注如何分步生成复杂对象。抽象工厂专门用于生产一系列相关对象。抽象工厂会马上返回产品,生成器则允许你在获取产品前执行一些额外构造步骤。
• 抽象工厂模式通常基于一组工厂方法,但你也可以使用原型模式来生成这些类的方法。
• 当只需对客户端代码隐藏子系统创建对象的方式时,你可以使用抽象工厂来代替外观。
• 你可以将抽象工厂和桥接搭配使用。如果由桥接定义的抽象只能与特定实现合作,这一模式搭配就非常有用。在这种情况下,抽象工厂可以对这些关系进行封装,并且对客户端代码隐藏其复杂性。
• 抽象工厂、生成器和原型都可以用单例来实现。