本文将借助C++来介绍抽象工厂模式。
设想小新接到客户需求,需要建造一个房间,该房间非常简单,由门、窗和墙组成。客户希望通过CreateRoom函数来完成房间的建造。
小新创建了四个类Room、Door、Window、Wall分别表示房间、门、窗和墙,很快完成了该函数的实现。
Room* CreateRoom() {
Room* aRoom = new Room;
Door* aDoor = new Door;
Window* aWindow = new Window;
Wall* aWall = new Wall;
aRoom->AddDoor(aDoor);
aRoom->AddWindow(aWindow);
aRoom->AddWall(aWall);
return aRoom;
}
客户使用这几行代码轻松的建了一个房间,非常高兴,于是又提出来想再建造一个房间,不过这次要木门、隔音窗和绿墙。小新很高兴,这不是和之前一样嘛,马上派生出三个类WoodenDoor、SoundProofWindow、GreenWall来表示木门、隔音窗和绿墙,并告诉客户,把之前的Door、Window和Wall都替换成新的就行了,客户看了后直皱眉头,对小新说,能不能把新型房间的建造变得简单点,每次都需要修改这么多地方,万一有个地方遗漏了,那损失就大了。
回到家后小新开始反省自己的松懈和冲动,也开始思考客户的需求。怎样才能让CreateRoom和房间的实现分离呢?怎样才能让CreateRoom易于产生新型房间呢?怎样才能让门窗墙的创建根据需求指向不同的实现呢?敏锐的小新马上想起了多态。手指一阵敲击,小新写出了下面的类。
class RoomFactory {
public:
RoomFactory();
virtual Room* MakeRoom() const
{ reutrn new Room; }
virtual Door* MakeDoor() const
{ return new Door; }
virtual Window* MakeWindow() const
{ return new Window; }
virtual Wall* MakeWall() const
{ return new Wall; }
};
CreateRoom的实现也变成了下面的方式。
Room* CreateRoom (RoomFactory& factory) {
Room* aRoom = factory.MakeRoom();
Door* aDoor = factory.MakeDoor();
Window* aWindow = factory.MakeWindow();
Wall* aWall = factory.MakeWall();
aRoom->AddDoor(aDoor);
aRoom->AddWindow(aWindow);
aRoom->AddWall(aWall);
return aRoom;
}
CreateRoom通过传入函数中的RoomFactory对象来完成房间的创建。小新很清楚,因为RoomFactory的成员函数是虚函数,因此可以通过虚表指针指向派生类中的相关实现。为了实现客户要求的新房间,小新马上实现了一个新类,这里取WoodenDoor、SoundProofWindow、GreenWall的首字母来命名该类为WsgRoomFactory。
class WsgRoomFactory : public RoomFactory {第二天见到客户,小新自信的拿出了自己的新方案,首先创建了一个原始房间。
public:
WsgRoomFactory();
virtual WoodenDoor* MakeDoor() const
{ return new WoodenDoor; }
virtual SoundProofWindow* MakeWindow() const
{ return new SoundProofWindow; }
virtual GreenWall* MakeWall() const
{ return new GreenWall; }
};
RoomFactory rf;然后将RoomFactory替换成WsgRoomFactory,创建了一个新型房间。
CreateRoom(rf);
WsgRoomFactory wrf;客户看了后很高兴,不住夸赞小新业务好,小新一激动,又造个红色的房间。
CreateRoom(wrf);
public RRoomFactory : public RoomFactory {并且告诉客户,我们的RoomFactory就是一个工厂,您想要什么房间、门、窗和墙,我们事先把产线给配好,您尽管拿去装配。
public:
RRoomFactory();
virtual RedWall* MakeWall() const
{ return new RedWall; }
};
RRoomFactory rrf;
CreateRoom(rrf);
经过这两天的工作,小新总结如下(参考《设计模式》一书):
抽象工厂模式的适用场景如下:
1、系统独立与产品的创建,如本例中房间的构建方式并不影响CreateRoom函数内的代码实现。
2、系统需要由多个配置中的某一项实现,如本例中房间的构建可以选择普通、木隔音绿和红三种方式中的一个。
3、想只提供类的接口而不是实现时,如本例中,CreateRoom函数并不知晓RoomFactory中的具体实现,只是调用了相应接口。
4、当你要强调一系列相关的产品对象的设计以便进行联合使用时。
使用抽象工厂模式的优点:
1、系统与类的实现分离。
2、易于更换产品。
3、有利于产品的一致性。
总结完后,小新非常高兴,有点飘飘然,这时候接到了客户的电话,是不是又要夸奖我?小新窃喜。
“小新啊,前面干的不错,现在我需要造一间有床的房子。”
小新收起了笑容。这便是抽象工厂模式的缺点:难以扩展抽象工厂来产生新种类产品,因为添加或者删除接口会影响到所有子类的使用。