工厂方法是一种创建设计模式,即与对象创建相关。在工厂模式中,我们创建对象而不将创建逻辑暴露给客户端,客户端使用相同的通用接口来创建新类型的对象。
这个想法是使用一个静态成员函数(静态工厂方法)来创建和返回实例,对用户隐藏类模块的细节。
工厂模式是创建对象的核心设计原则之一,允许客户端以与库的类层次结构没有紧密耦合的方式创建库的对象(如下所述)。
当我们谈论图书馆和客户时是什么意思?
库是由某些第三方提供的东西,它公开一些公共 API,客户端调用这些公共 API 以完成其任务。一个非常简单的例子可以是 Android 操作系统提供的不同类型的视图。
为什么是工厂模式?
让我们通过一个例子来理解它:
// A design without factory pattern
#include
using namespace std;
// Library classes
class Vehicle {
public:
virtual void printVehicle() = 0;
};
class TwoWheeler : public Vehicle {
public:
void printVehicle() {
cout << "I am two wheeler" << endl;
}
};
class FourWheeler : public Vehicle {
public:
void printVehicle() {
cout << "I am four wheeler" << endl;
}
};
// Client (or user) class
class Client {
public:
Client(int type) {
// Client explicitly creates classes according to type
if (type == 1)
pVehicle = new TwoWheeler();
else if (type == 2)
pVehicle = new FourWheeler();
else
pVehicle = NULL;
}
~Client() {
if (pVehicle)
{
delete[] pVehicle;
pVehicle = NULL;
}
}
Vehicle* getVehicle() {
return pVehicle;
}
private:
Vehicle *pVehicle;
};
// Driver program
int main() {
Client *pClient = new Client(1);
Vehicle * pVehicle = pClient->getVehicle();
pVehicle->printVehicle();
return 0;
}
输出:
I am two wheeler
上面的设计有什么问题?
正如您在上面的示例中必须观察到的那样,客户端在构造其对象期间根据某些输入创建 TwoWheeler 或 FourWheeler 对象。
比如说,图书馆引入了一个新类 ThreeWheeler 来合并三轮车。会发生什么?如果在条件阶梯中创建 ThreeWheeler 对象,客户端最终将链接一个新的 else。这反过来又需要重新编译客户端。因此,每次在库端进行新的更改时,Client 都需要在其末尾进行一些相应的更改并重新编译代码。听起来很糟糕?这是一种非常糟糕的设计实践。
如何避免问题?
答案是,创建一个静态(或工厂)方法。让我们看看下面的代码。
// C++ program to demonstrate factory method design pattern
#include
using namespace std;
enum VehicleType {
VT_TwoWheeler, VT_ThreeWheeler, VT_FourWheeler
};
// Library classes
class Vehicle {
public:
virtual void printVehicle() = 0;
static Vehicle* Create(VehicleType type);
};
class TwoWheeler : public Vehicle {
public:
void printVehicle() {
cout << "I am two wheeler" << endl;
}
};
class ThreeWheeler : public Vehicle {
public:
void printVehicle() {
cout << "I am three wheeler" << endl;
}
};
class FourWheeler : public Vehicle {
public:
void printVehicle() {
cout << "I am four wheeler" << endl;
}
};
// Factory method to create objects of different types.
// Change is required only in this function to create a new object type
Vehicle* Vehicle::Create(VehicleType type) {
if (type == VT_TwoWheeler)
return new TwoWheeler();
else if (type == VT_ThreeWheeler)
return new ThreeWheeler();
else if (type == VT_FourWheeler)
return new FourWheeler();
else return NULL;
}
// Client class
class Client {
public:
// Client doesn't explicitly create objects
// but passes type to factory method "Create()"
Client()
{
VehicleType type = VT_ThreeWheeler;
pVehicle = Vehicle::Create(type);
}
~Client() {
if (pVehicle) {
delete[] pVehicle;
pVehicle = NULL;
}
}
Vehicle* getVehicle() {
return pVehicle;
}
private:
Vehicle *pVehicle;
};
// Driver program
int main() {
Client *pClient = new Client();
Vehicle * pVehicle = pClient->getVehicle();
pVehicle->printVehicle();
return 0;
}
输出:
I am three wheeler
在上面的例子中,我们已经将用于创建对象的类型选择与客户端完全分离。该库现在负责根据输入决定要创建的对象类型。客户端只需要调用库的工厂 Create 方法并传递它想要的类型,而无需担心对象创建的实际实现。
感谢 Rumplestiltskin 提供上述解释。
工厂方法的其他例子:
- 比如说,在“绘图”系统中,根据用户的输入,可以绘制不同的图片,如正方形、矩形、圆形。在这里,我们可以使用工厂方法根据用户的输入创建实例。对于添加新类型的形状,无需更改客户端的代码。
- 另一个例子:在旅游网站,我们可以预订火车票,也可以预订巴士票和机票。在这种情况下,用户可以将其旅行类型指定为“公共汽车”、“火车”或“航班”。
这里我们有一个带有静态成员函数“GetObject”的抽象类“AnyTravel”,它根据用户的旅行类型,将创建和返回“BusTravel”或“TrainTravel”对象。 “BusTravel”或“TrainTravel”具有乘客姓名、出发地、目的地参数等通用功能。
感谢 Abhijit Saha 提供了前两个示例。