本文通过一个例子简单介绍简单工厂模式、工厂模式和抽象工厂模式。
1.简单工厂(静态)
假如我想换个手机,换什么手机呢?可以考虑苹果或者华为手机,那我们用简单工厂模式来实现这个功能:
我们关注的产品是手机,那生产手机的工厂有苹果,有华为,用户也不确定选哪种怎么办?这里用简单工厂模式:定义两个枚举类型,然后写一个工厂类,根据用户传入的枚举类型生产对应品牌的手机:
手机基类:
#pragma once
class MyPhone
{
public:
MyPhone(double price);
~MyPhone();
double getPrice() { return m_price; }
private:
double m_price;
};
#include "MyPhone.h"
MyPhone::MyPhone(double price) :m_price(price)
{
}
MyPhone::~MyPhone()
{
}
苹果手机:
#pragma once
#include "MyPhone.h"
class Phone_Apple:public MyPhone
{
public:
Phone_Apple(double price);
~Phone_Apple();
};
#include "Phone_Apple.h"
#include "stdio.h"
Phone_Apple::Phone_Apple(double price):MyPhone(price)
{
printf("This is iPhone!");
}
Phone_Apple::~Phone_Apple()
{
}
华为手机:
#pragma once
#include "MyPhone.h"
class Phone_Huawei :public MyPhone
{
public:
Phone_Huawei(double price);
~Phone_Huawei();
};
#include "Phone_Huawei.h"
#include "stdio.h"
Phone_Huawei::Phone_Huawei(double price) :MyPhone(price)
{
printf("This is HUAWEI!");
}
Phone_Huawei::~Phone_Huawei()
{
}
简单工厂类:
#pragma once
#include "MyPhone.h"
enum phoneType
{
APPLE_Phone,
HUAWEI_Phone
};
class SimpleFactory
{
public:
SimpleFactory();
~SimpleFactory();
MyPhone* createPhone(phoneType type);
};
#include "SimpleFactory.h"
#include "Phone_Apple.h"
#include "Phone_Huawei.h"
SimpleFactory::SimpleFactory()
{
}
SimpleFactory::~SimpleFactory()
{
}
MyPhone* SimpleFactory::createPhone(phoneType type)
{
MyPhone* phone = nullptr;
switch (type)
{
case APPLE_Phone:
phone = new Phone_Apple(6000);
break;
case HUAWEI_Phone:
phone = new Phone_Huawei(5600);
break;
}
return phone;
}
用户根据自定义类型修改创建:
SimpleFactory* factory = new SimpleFactory();
//用户指定要苹果
MyPhone* phone = factory->createPhone(APPLE_Phone);
cout << "Price: " << phone->getPrice() << endl;
delete phone;
delete factory;
2.工厂模式
这里的工厂类似于一个手机销售店,你需要什么手机就提供什么手机,没有问题,如果用户增加了需求,想要添加三星、OPPO等,怎么办?
- 可以分别继承Myphone类,分别实现不同产品;
- 在SimpleFactory类中添加对应类别;
- 在createPhone方法中添加对应类别(还要引入对应的新的类和头文件);
- 可通过配置文件等方式准备好已有的类型供用户选择调用;
很明显每次都要对原文件修改,如何避免呢?这里进入工厂模式:将生产手机的工厂抽象出来,然后将具体的生产厂家继承自这个抽象工厂,分别创建自己的产品:
抽象工厂类:
#pragma once
#include "MyPhone.h"
class IFactory
{
public:
IFactory();
~IFactory();
virtual MyPhone* createPhone() = 0;
};
华为工厂:
#pragma once
#include "IFactory.h"
#include "MyPhone.h"
class HuaweiFactory : public IFactory
{
public:
HuaweiFactory();
~HuaweiFactory();
virtual MyPhone* createPhone();
};
#include "HuaweiFactory.h"
#include "Phone_Huawei.h"
HuaweiFactory::HuaweiFactory()
{
}
HuaweiFactory::~HuaweiFactory()
{
}
MyPhone* HuaweiFactory::createPhone()
{
MyPhone* phone = new Phone_Huawei(5600);
return phone;
}
苹果工厂:
#pragma once
#include "IFactory.h"
#include "MyPhone.h"
class IphoneFactory : public IFactory
{
public:
IphoneFactory();
~IphoneFactory();
virtual MyPhone* createPhone();
};
#include "IphoneFactory.h"
#include "Phone_Apple.h"
IphoneFactory::IphoneFactory()
{
}
IphoneFactory::~IphoneFactory()
{
}
MyPhone* IphoneFactory::createPhone()
{
MyPhone* phone = new Phone_Apple(6000);
return phone;
}
//3.2 工厂模式
IFactory* factory = new IphoneFactory();
MyPhone* phone = factory->createPhone();
cout << "Price: " << phone->getPrice() << endl;
IFactory* factory1 = new HuaweiFactory();
MyPhone* phone1 = factory1->createPhone();
cout << "Price: " << phone1->getPrice() << endl;
delete phone;
delete phone1;
delete factory;
delete factory1;
3.抽象工厂模式
这时,如果用户需要增加产品类型,比如华为的平板、苹果的平板怎么办?这就要引入抽象工厂模式了。
- 将产品类进行抽象(这里可能会涉及多种产品);
- 写出具体的产品类;
- 将工厂类进行抽象;
- 具体工厂生产对应的产品(一个工厂可以生产自己品牌的多种产品)
在原来代码基础上进行修改:
产品抽象类:
#pragma once
class MyPhone
{
public:
MyPhone(double price);
~MyPhone();
double getPrice() { return m_price; }
private:
double m_price;
};
class MyPad
{
public:
MyPad(double price);
~MyPad();
double getPrice() { return m_price; }
private:
double m_price;
};
苹果产品类:
#pragma once
#include "MyPhone.h"
class Phone_Apple:public MyPhone
{
public:
Phone_Apple(double price);
~Phone_Apple();
};
class Pad_Apple :public MyPad
{
public:
Pad_Apple(double price);
~Pad_Apple();
};
华为产品类:
#pragma once
#include "MyPhone.h"
class Phone_Huawei :public MyPhone
{
public:
Phone_Huawei(double price);
~Phone_Huawei();
};
class Pad_Huawei :public MyPad
{
public:
Pad_Huawei(double price);
~Pad_Huawei();
};
抽象工厂类:
#pragma once
#include "MyPhone.h"
class IFactory
{
public:
IFactory();
~IFactory();
virtual MyPhone* createPhone() = 0;
virtual MyPad* createPad() = 0;
}
具体工厂类:
#pragma once
#include "IFactory.h"
#include "MyPhone.h"
#include "Phone_Apple.h"
class IphoneFactory : public IFactory
{
public:
IphoneFactory();
~IphoneFactory();
virtual MyPhone* createPhone(){
MyPhone* phone = new Phone_Apple(6000);
return phone;
}
virtual MyPad* createPad() {
MyPad* phone = new Pad_Apple(4900);
return phone;
}
};
#pragma once
#include "IFactory.h"
#include "MyPhone.h"
#include "Phone_Huawei.h"
class HuaweiFactory : public IFactory
{
public:
HuaweiFactory();
~HuaweiFactory();
virtual MyPhone* createPhone() {
MyPhone* phone = new Phone_Huawei(5600);
return phone;
}
virtual MyPad* createPad() {
MyPad* phone = new Pad_Huawei(4600);
return phone;
}
};
调用:
//3.3 抽象工厂模式
IFactory* factory = new HuaweiFactory();
MyPad* pad = factory->createPad();
cout << "Price: " << pad->getPrice() << endl;
MyPhone* phone = factory->createPhone();
cout << "Price: " << phone->getPrice() << endl;
delete pad;
delete phone;
delete factory;
4.总结对比
三种方法使用选择:
分别理解三种模式并不困难,关键就在于根据实际问题实际情况选用不同的模式,先总结如下思考方式,供参考:
- 当产品类型固定时可选择简单工厂模式(这里可以认为是零维的,即不用考虑其他维度);
- 当产品涉及到不同厂商时,将工厂抽象化,不同厂商实现大厂的接口(这里可以认为是一维的,除了产品自身还需考虑厂商问题);
- 当涉及到不同厂商的不同产品时,将工厂和产品分别抽象化(这里可以认为是二维的,考虑产品的种类以及厂商问题);
总之要尽量满足OOP七大原则:
- 开闭原则: 一个软件的实体应当对扩展开放,对修改关闭
- 依赖倒转原则: 要针对接口编程,不要针对实现编程
- 迪米特法则:只与你直接的朋友通信,而避免和陌生人通信
三种方式的对比:
简单(静态)工厂模式:
用来生产同一等级结构中的任意产品(对于增加新的产品,需要修改已有代码;
工厂方法模式:
用来生产同一等级结构中的固定产品(支持增加任意产品)
优点:
- 你可以避免创建者和具体产品之间的紧密耦合。
- 单一职责原则。你可以将产品创建代码放在程序的单一位置,从而使得代码更容易维护。
- 开闭原则。无需更改现有客户端代码,你就可以在程序中引入新的产品类型。
缺点:
- 应用工厂方法模式需要引入许多新的子类,代码可能会因此变得更复杂。最好的情况是将该模式引入创建者类的现有层次结构中。
抽象工厂模式:
围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。
优点:
- 应用工厂方法模式需要引入许多新的子类,代码可能会因此变得更复杂。最好的情况是将该模式引入创建者类的现有层次结构中。
缺点:
- 由于采用该模式需要向应用中引入众多接口和类,代码可能会比之前更加复杂。
参考文献:【精选】设计模式之工厂模式(简单工厂、工厂方法、抽象工厂)_简单工厂模式 抽象工厂模式-CSDN博客1. 工厂方法模式(Factory Method) (yuque.com)2. 抽象工厂模式(Abstract Factory) (yuque.com)