概述
工厂方法模式和前一篇文章中提到的简单工厂模式都属于创建型设计模式,它们都致力于解决对象创建的问题。但两者还是有一些重要区别的:简单工厂模式通常用于减少重复代码,并将对象的创建逻辑集中在一个地方,适用于产品种类较少且创建逻辑相对简单的情况;工厂方法模式让子类决定要实例化的具体类,适用于系统中有多个产品家族,或者希望将对象的创建委托给专门的子类的情况。
汽车制造集团是运用工厂方法模式的一个例子:假如它拥有多个品牌,每个品牌都有自己的生产线和车型系列,则集团总部可以被视为抽象的创建者,而每个品牌工厂则对应具体的创建者。在这种情况下,客户(比如:经销商、直接消费者)不需要知道汽车具体是如何生产的,他们只需要与工厂交互,并指定想要的品牌,工厂就会负责创建相应品牌的汽车实例。
基本原理
工厂方法模式的基本原理是:通过定义一个用于创建对象的接口,但让子类决定实例化哪一个具体的类。这样,工厂方法模式将对象的创建延迟到子类中进行,从而实现了更大的灵活性和扩展性。工厂方法模式包括如下四个核心组件。
1、产品接口。这是所有具体产品都必须实现的接口或抽象类,它定义了产品的公共行为。
2、具体产品。实现了产品接口的具体类,代表可以被创建的实际对象。
3、创建者。这是一个包含工厂方法的类或接口,该方法声明了创建产品对象的接口,但是返回的是产品接口类型。创建者可能还提供了一些其他方法,以使用这些产品。
4、具体创建者。继承自创建者,并且实现了工厂方法以创建特定的具体产品。
基于上面的核心组件,工厂方法模式的实现主要有以下六个步骤。
1、定义产品接口。首先,定义一个产品接口或抽象类,规定所有具体产品必须实现的方法。
2、实现具体产品。然后,为每种需要创建的产品类型创建具体的类,它们各自实现了产品接口。
3、定义创建者接口。创建一个创建者类或接口,其中声明了一个工厂方法。这个方法返回一个产品接口类型的对象,但是并不实现具体的创建逻辑。
4、实现具体创建者。对于每个具体产品,创建一个对应的创建者子类,它实现了工厂方法来创建具体的产品实例。
5、编写客户端代码。客户端代码与创建者交互,而不是直接与具体产品打交道。当需要创建一个产品时,客户端调用创建者中的工厂方法,而具体的创建过程由创建者的子类负责处理。
6、扩展系统。当需要添加新的产品时,只需创建一个新的具体产品类以及相应的具体创建者类,而不必修改现有的代码。
实战解析
在下面的实战代码中,我们使用工厂方法模式创建了多个图形产品的具体工厂。
CShape是所有图形产品的公共接口和基类,定义了一个Draw方法。CCircle和CRectangle作为具体的产品类,分别实现了绘图逻辑。
CShapeFactory是抽象的创建者,它声明但未实现创建图形的方法。CCircleFactory和CRectangleFactory则是具体的创建者类,它们各自实现了创建特定类型图形对象的逻辑。
客户端代码通过选择不同的具体创建者CCircleFactory或CRectangleFactory,来间接创建并使用具体的产品实例,而不需要直接依赖于这些具体的产品类,从而提高了代码的灵活性和可扩展性。
#include <iostream>
#include <string>
using namespace std;
// 产品接口
class CShape
{
public:
virtual void Draw() const = 0;
virtual ~CShape() {}
};
// 具体产品
class CCircle : public CShape
{
public:
void Draw() const
{
cout << "Draw Circle" << endl;
}
};
// 具体产品
class CRectangle : public CShape
{
public:
void Draw() const
{
cout << "Draw Rectangle" << endl;
}
};
// 抽象创建者,声明了工厂方法CreateShape,但未提供实现
class CShapeFactory
{
public:
virtual ~CShapeFactory() {}
virtual CShape* CreateShape() const = 0;
};
// 具体创建者,创建CCircle实例
class CCircleFactory : public CShapeFactory
{
public:
CShape* CreateShape() const
{
return new CCircle();
}
};
// 具体创建者,创建CRectangle实例
class CRectangleFactory : public CShapeFactory
{
public:
CShape* CreateShape() const
{
return new CRectangle();
}
};
int main()
{
// 客户端代码
CShapeFactory* pFactory = new CCircleFactory();
CShape* pShape = pFactory->CreateShape();
pShape->Draw();
delete pShape;
delete pFactory;
pFactory = new CRectangleFactory();
pShape = pFactory->CreateShape();
pShape->Draw();
delete pShape;
delete pFactory;
return 0;
}
总结
在工厂方法模式中,系统可以通过添加新的具体产品及其对应的具体创建者来扩展功能,而无需修改现有代码。这样,客户端代码与具体的产品类之间进行了解耦,提高了代码的可维护性和复用性。另外,通过工厂方法返回的产品接口类型,可以在运行时动态地选择不同的具体产品实例,增强了灵活性。
但工厂方式模式增加了类的数量,每一个具体的产品都需要有一个对应的创建者,这会导致类的数量增多,使系统变得复杂。如果应用中只需要少量的不同类型的对象,那么使用工厂方法模式可能是一种过度设计。