抽象工厂模式是一种创建型设计模式,它提供了一种在不指定具体产品类的情况下创建一系列相关或依赖对象的方法。
抽象工厂模式分为四个角色:抽象工厂、具体工厂、抽象产品、具体产品。
抽象工厂和工厂方法其实很类似,但也有一定的区别:
抽象工厂模式关注一系列产品对象的创建
工厂方法模式关注单个产品对象的创建
举例:
假设我们有两个产品族:手机(Phone)和电脑(Laptop),它们有不同的型号:苹果(Apple)和华为(HuaWei)。
// 手机接口-抽象产品
class Phone
{
public:
virtual ~Phone() {}
virtual void MakeCall() = 0;
};
// 电脑接口-抽象产品
class Laptop
{
public:
virtual ~Laptop() {}
virtual void PlayGame() = 0;
};
// 华为手机-具体产品
class HuaWeiPhone
: public Phone
{
public:
virtual void MakeCall() override
{
std::cout << "华为手机打电话" << std::endl;
}
};
// 华为电脑-具体产品
class HuaWeiLaptop
: public Laptop
{
public:
virtual void PlayGame() override
{
std::cout << "华为电脑玩游戏" << std::endl;
}
};
// 苹果手机-具体产品
class ApplePhone
: public Phone
{
public:
virtual void MakeCall() override
{
std::cout << "苹果手机打电话" << std::endl;
}
};
// 苹果电脑-具体产品
class AppleLaptop
: public Laptop
{
public:
virtual void PlayGame() override
{
std::cout << "苹果电脑玩游戏" << std::endl;
}
};
// 抽象工厂
class AbstractFactory
{
public:
virtual ~AbstractFactory() {}
virtual std::shared_ptr<Phone> CreatePhone() = 0;
virtual std::shared_ptr<Laptop> CreateLaptop() = 0;
};
// 华为工厂-具体工厂
class HuaWeiFactory
: public AbstractFactory
{
public:
virtual std::shared_ptr<Phone> CreatePhone() override
{
return std::make_shared<HuaWeiPhone>();
}
virtual std::shared_ptr<Laptop> CreateLaptop() override
{
return std::make_shared<HuaWeiLaptop>();
}
};
// 苹果工厂-具体工厂
class AppleFactory
: public AbstractFactory
{
public:
virtual std::shared_ptr<Phone> CreatePhone() override
{
return std::make_shared<ApplePhone>();
}
virtual std::shared_ptr<Laptop> CreateLaptop() override
{
return std::make_shared<AppleLaptop>();
}
};
测试
void TestAbstractFactory()
{
// 创建苹果工厂
std::shared_ptr<AbstractFactory> apple_factory = std::make_shared<AppleFactory>();
// 创建华为工厂
std::shared_ptr<AbstractFactory> huawei_factory = std::make_shared<HuaWeiFactory>();
// 通过苹果工厂创建苹果电脑和苹果手机
std::shared_ptr<Phone> apple_phone = apple_factory->CreatePhone();
std::shared_ptr<Laptop> apple_laptop = apple_factory->CreateLaptop();
// 通过华为工厂创建华为电脑和华为手机
std::shared_ptr<Phone> huawei_phone = huawei_factory->CreatePhone();
std::shared_ptr<Laptop> huawei_laptop = huawei_factory->CreateLaptop();
// 使用苹果电脑和手机
apple_phone->MakeCall();
apple_laptop->PlayGame();
// 使用华为电脑和手机
huawei_phone->MakeCall();
huawei_laptop->PlayGame();
}
输出:
苹果手机打电话
苹果电脑玩游戏
华为手机打电话
华为电脑玩游戏
我们通过抽象工厂接口创建了一个苹果工厂和华为工厂,又通过华为工厂接口创建了华为电脑和华为手机(苹果同理),这样的话我们就可以使用华为电脑和手机。
通过这种方式,我们就绕开了new的方式去创建对象。
抽象工厂遵循的设计原则:
- 依赖倒置原则:通过引入抽象接口,实现了具体产品的实现细节与客户端代码(测试代码或使用代码)的解耦。客户端只需要通过抽象接口创建对象,不需要关心具体的产品类。这样就是实现了高层模块(客户端代码)依赖抽象接口,而不依赖具体的低层模块(具体的产品实现)。
- 开放封闭原则:通过引入抽象接口,允许添加工厂和产品,而不需要修改已有代码,实现了对扩展开放、对修改关闭。
- 单一职责原则:抽象工厂模式将产品的创建封装在具体工厂类中,每个工厂又负责创建特定的产品族,使得每一个类只有一个职责。
- 接口隔离原则:通过引入抽象接口,将产品对象的创建方法和具体的实现细节隔离开,客户端代码不需要关心具体产品的实现,只需要和抽象接口进行交互,避免了对不需要的方法进行依赖。
抽象工厂模式适用于以下场景:
- 系统需要独立于它的产品的创建、组合和表示时
- 系统需要一组相关产品对象,并且希望统一地对待它们
- 系统需要在运行时切换不同的产品族
抽象工厂模式的优点:
- 将客户端代码于具体产品的实现进行解耦,使客户端可以灵活应用各种产品。
缺点:
- 增加新的产品族比较困难,需要修改抽象工厂的接口
- 当创建的产品只有一个时,退化成工厂方法模式