工厂模式分为简单工厂模式、工厂方法模式和抽象工厂模式。
1.简单工厂模式
简单工厂模式又叫静态方法模式(因为工厂类定义了一个静态方法)。
将“类实例化的操作”与“使用对象的操作”分开,让使用者不用知道具体参数就可以实例化出所需要的“产品”类,从而避免了在客户端代码中显式指定,实现了解耦。也就是说,使用者可直接消费产品而不需要知道其生产的细节。
模式组成:
组成 | 关系 | 作用 |
抽象产品(Product) | 具体产品的父类 | 描述产品的公共接口 |
具体产品(Concrete Product) | 抽象产品的子类;工厂类创建的目标类 | 描述生产的具体产品 |
工厂(Factor) | 被外界调用 | 根据传入不同参数从而创建不同具体产品类的实例 |
使用步骤:
- 创建抽象产品类Product :定义产品的公共接口
- 创建具体产品类(继承抽象产品类):定义生产的具体产品
- 创建工厂类:通过创建静态方法传入不同参数,从而创建不同具体产品类的实例
- 外界通过调用工厂类的静态方法,传入不同参数从而创建不同具体产品类的实例
实列:某加工厂推出三个产品,使用简单工厂模式实现三种产品的生成
①创建抽象产品类Product:
class Product
{
public:
virtual void Show() = 0;
};
②创建具体产品类(继承抽象产品类):
class ProductA : public Product
{
public:
void Show()
{
cout<<"I'm ProductA"<<endl;
}
};
class ProductB : public Product
{
public:
void Show()
{
cout<<"I'm ProductB"<<endl;
}
};
class ProductC : public Product
{
public:
void Show()
{
cout<<"I'm ProductC"<<endl;
}
};
③创建工厂类:通过创建静态方法传入不同参数,从而创建不同具体产品类的实例。
typedef enum ProductTypeTag
{
TypeA,
TypeB,
TypeC
}PRODUCTTYPE;
class Factory
{
public:
static Product* CreateProduct(PRODUCTTYPE type)
{
switch (type)
{
case TypeA:
return new ProductA();
case TypeB:
return new ProductB();
case TypeC:
return new ProductC();
default:
return NULL;
}
}
};
④外界通过调用工厂类的静态方法,传入不同参数从而创建不同具体产品类的实例
int main(int argc, char *argv[])
{
//创造工厂对象
Factory *ProductFactory = new Factory();
//从工厂对象创造产品A对象
Product *productObjA = ProductFactory->CreateProduct(TypeA);
if (productObjA != NULL)
productObjA->Show();
Product *productObjB = ProductFactory->CreateProduct(TypeB);
if (productObjB != NULL)
productObjB->Show();
Product *productObjC = ProductFactory->CreateProduct(TypeC);
if (productObjC != NULL)
productObjC->Show();
delete ProductFactory;
ProductFactory = NULL;
delete productObjA;
productObjA = NULL;
delete productObjB;
productObjB = NULL;
delete productObjC;
productObjC = NULL;
return 0;
}
优缺点:
优点:
- 把初始化实例时的工作放到工厂里进行,使代码更容易维护。
- 将“类实例化的操作”与“使用对象的操作”分开,让使用者不用知道具体参数就可以实例化出所需要的“产品”类,
缺点:
- 工厂类集中了所有实例(产品)的创建逻辑,一旦这个工厂不能正常工作,整个系统都会受到影响;
- 违背“开放 - 关闭原则”,一旦添加新产品就不得不修改工厂类的逻辑,这样就会造成工厂逻辑过于复杂。
- 简单工厂模式由于使用了静态工厂方法,静态方法不能被继承和重写,会造成工厂角色无法形成基于继承的等级结构。
2.工厂方法模式
针对简答工厂模式问题,设计了工厂方法模式。工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。
将类的实例化(具体产品的创建)延迟到工厂类的子类(具体工厂)中完成,即由子类来决定应该实例化(创建)哪一个类。
之所以可以解决简单工厂的问题,是因为工厂方法模式把具体产品的创建推迟到工厂类的子类(具体工厂)中,此时工厂类不再负责所有产品的创建,而只是给出具体工厂必须实现的接口,这样工厂方法模式在添加新产品的时候就不修改工厂类逻辑而是添加新的工厂子类,符合开放封闭原则。
模式组成:
组成 | 关系 | 作用 |
抽象产品(Product) | 具体产品的父类 | 描述具体产品的公共接口 |
具体产品(Concrete Product) | 抽象产品的子类;工厂类创建的目标类 | 描述生产的具体产品 |
抽象工厂(Factor) | 具体工厂的父类 | 描述具体工厂的公共接口 |
具体工厂(Concrete Factor) | 抽象工厂的子类;被外界调用 | 描述具体工厂 |
使用步骤:
- 创建抽象产品类 ,定义具体产品的公共接口;
- 创建具体产品类(继承抽象产品类):定义生产的具体产品;
- 创建抽象工厂类,定义具体工厂的公共接口;
- 创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;
- 外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例
实例:某加工厂原来只生产A类产品,但新的订单要求生产B类产品,由于改变原来工厂的配置比较困难,因此开设工厂B生产B类产品。
#include <iostream>
using namespace std;
//1.创建抽象产品类
class Product
{
public:
virtual void Show() = 0;
};
//2.创建具体产品类(继承抽象产品类)
class ProductA : public Product
{
public:
void Show()
{
cout<< "I'm ProductA"<<endl;
}
};
class ProductB : public Product
{
public:
void Show()
{
cout<< "I'm ProductB"<<endl;
}
};
//3.创建抽象工厂类
class Factory
{
public:
virtual Product *CreateProduct() = 0;
};
//4.创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;
class FactoryA : public Factory
{
public:
Product *CreateProduct()
{
return new ProductA ();
}
};
class FactoryB : public Factory
{
public:
Product *CreateProduct()
{
return new ProductB ();
}
};
//5.外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例
int main(int argc , char *argv [])
{
Factory *factoryA = new FactoryA ();
Product *productA = factoryA->CreateProduct();
productA->Show();
Factory *factoryB = new FactoryB ();
Product *productB = factoryB->CreateProduct();
productB->Show();
if (factoryA != NULL)
{
delete factoryA;
factoryA = NULL;
}
if (productA != NULL)
{
delete productA;
productA = NULL;
}
if (factoryB != NULL)
{
delete factoryB;
factoryB = NULL;
}
if (productB != NULL)
{
delete productB;
productB = NULL;
}
system("pause");
return 0;
}
优缺点:
优点:
- 符合开-闭原则。新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可。(简单工厂模式需要修改工厂类的判断逻辑)
- 符合单一职责原则。每个具体工厂类只负责创建对应的产品。(简单工厂中的工厂类存在复杂的switch逻辑判断)
- 不使用静态工厂方法,可以形成基于继承的等级结构。(简单工厂模式的工厂类使用静态工厂方法)
缺点:
- 添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度
- 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度
- 一个具体工厂只能创建一种具体产品
3.抽象工厂模式
工厂方法模式存在一个严重的问题:一个具体工厂只能创建一类产品;而在实际过程中,一个工厂往往需要生产多类产品。使用了一种新的设计模式:抽象工厂模式。
定义:创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类;具体的工厂负责实现具体的产品实例。
允许使用抽象的接口来创建一组相关产品,而不需要知道或关心实际生产出的具体产品是什么,这样就可以从具体产品中被解耦。
模式组成:
组成 | 关系 | 作用 |
抽象产品族(AbstractProduct | 抽象产品的父类 | 描述抽象产品的公共接口 |
抽象产品(Product) | 具体产品的父类 | 描述具体产品的公共接口 |
具体产品(Concrete Product) | 抽象产品的子类;工厂类创建的目标类 | 描述生产的具体产品 |
抽象工厂(Factor) | 具体工厂的父类 | 描述具体工厂的公共接口 |
具体工厂(Concrete Factor) | 抽象工厂的子类;被外界调用 | 描述具体工厂 |
使用步骤:
- 创建抽象产品族类 ,定义抽象产品的公共接口;
- 创建抽象产品类 (继承抽象产品族类),定义具体产品的公共接口;
- 创建具体产品类(继承抽象产品类) & 定义生产的具体产品;
- 创建抽象工厂类,定义具体工厂的公共接口;
- 创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;
- 客户端通过实例化具体的工厂类,并调用其创建不同目标产品的方法 创建不同具体产品类的实例
实例:某厂有两个加工厂A和B分别生产鞋和衣服,随着订单的增加,A厂所在地有了衣服的订单,B厂所在地有了鞋子的订单,再开新的工厂显然是不现实的,因此在原来的工厂增加生产需求的功能,即A生产鞋+衣服,B生产衣服+鞋。
#include <iostream>
using namespace std;
//这个代码没有抽象产品族类
// 抽象产品A
class ProductA
{
public:
virtual void Show() = 0;
};
//具体的产品
class ProductA1 : public ProductA
{
public:
void Show()
{
cout<<"I'm ProductA1"<<endl;
}
};
class ProductA2 : public ProductA
{
public:
void Show()
{
cout<<"I'm ProductA2"<<endl;
}
};
// 抽象产品B
class ProductB
{
public:
virtual void Show() = 0;
};
class ProductB1 : public ProductB
{
public:
void Show()
{
cout<<"I'm ProductB1"<<endl;
}
};
class ProductB2 : public ProductB
{
public:
void Show()
{
cout<<"I'm ProductB2"<<endl;
}
};
// Factory
class Factory
{
public:
virtual ProductA *CreateProductA() = 0;
virtual ProductB *CreateProductB() = 0;
};
//具体工厂A生产A1和B1
class Factory1 : public Factory
{
public:
ProductA *CreateProductA()
{
return new ProductA1();
}
ProductB *CreateProductB()
{
return new ProductB1();
}
};
class Factory2 : public Factory
{
ProductA *CreateProductA()
{
return new ProductA2();
}
ProductB *CreateProductB()
{
return new ProductB2();
}
};
int main(int argc, char *argv[])
{
Factory *factoryObj1 = new Factory1();
ProductA *productObjA1 = factoryObj1->CreateProductA();
ProductB *productObjB1 = factoryObj1->CreateProductB();
productObjA1->Show();
productObjB1->Show();
Factory *factoryObj2 = new Factory2();
ProductA *productObjA2 = factoryObj2->CreateProductA();
ProductB *productObjB2 = factoryObj2->CreateProductB();
productObjA2->Show();
productObjB2->Show();
if (factoryObj1 != NULL)
{
delete factoryObj1;
factoryObj1 = NULL;
}
if (productObjA1 != NULL)
{
delete productObjA1;
productObjA1= NULL;
}
if (productObjB1 != NULL)
{
delete productObjB1;
productObjB1 = NULL;
}
if (factoryObj2 != NULL)
{
delete factoryObj2;
factoryObj2 = NULL;
}
if (productObjA2 != NULL)
{
delete productObjA2;
productObjA2 = NULL;
}
if (productObjB2 != NULL)
{
delete productObjB2;
productObjB2 = NULL;
}
system("pause");
return 0;
}
优缺点:
优点:
- 抽象工厂模式将具体产品的创建延迟到具体工厂的子类中,这样将对象的创建封装起来,可以减少客户端与具体产品类之间的依赖,从而使系统耦合度低,这样更有利于后期的维护和扩展;
- 新增一种产品类时,只需要增加相应的具体产品类和相应的工厂子类即可
缺点:
- 抽象工厂模式很难支持新种类产品的变化。因为抽象工厂接口中已经确定了可以被创建的产品集合,如果需要添加新产品,此时就必须去修改抽象工厂的接口,这样就涉及到抽象工厂类的以及所有子类的改变