设计模式-创建型-抽象工厂

GOF常读常新,相信下次再来回顾时,理解又会更深一层了。加油。


当我阅读创建型模式时,我始终这样提醒着自己:抓住变化点,隔离之,区分哪里是变化的,哪里是相对不变的。

创建型模式解决的即是new的问题,先看下面的例子,理解new所带来的麻烦。直接使用GOF上面的例子来说明,类似Room,Door的说明就不再重复了

Maze* MazeGame::CreateMaze()
{
	Maze* aMaze	= new Maze;
	Room* r1	= new Room(1);
	Room* r2	= new Room(2);
	Door* theDr	= new Door(r1,r2);
	
	...
}

当需要新的类型的Room1,Door3时,我们可以这样修改CreateMaze

Maze* MazeGame::CreateMaze()
{
	Maze* aMaze	= new Maze;
	Room* r1	= new Room1(1);
	Room* r2	= new Room2(2);
	Door* theDr	= new Door3(r1,r2);
	
	...
}

此时希望使用子类Room4时,我们同样需要修改CreateMaze才能适应这样的变化。即使在CreateMaze里面加个switch case,并传参以决定new什么样的类型,当Room扩展出新的子类时,switch case语句同样需要修改。更重要的是,CreateMaze可能会很复杂,它依赖一个算法来创建迷宫,而且创建规则是与具体的类型无关的直接使用new使得CreateMaze函数依赖了具体的类名。使得每次变化,都需要来修改CreateMaze。

new所带来的麻烦,你看到了吗?new即是程序中的变化点

既然变化点找到了,然后呢。照之前所说,隔离之,提炼出接口,达到依赖接口(MakeRoom(...)),也不依赖具体实现的目的(Room,Room1)。

class MazeFactory
{
public:
	MazeFactory();
	
	virtual Maze* MakeMaze() const
	{
		return new Maze;
	}
	
	virtual Room* MakeRoom() const
	{
		return new Room();
	}
	
	virtual Door* MakeDoor(Room* r1, Room* r2) const
	{
		return new Door(r1, r2);
	}
	
	...
}

而此时的CreateMaze()可以是这样的

Maze* MazeGame::CreateMaze(MazeFactory& factory)
{
	Maze* aMaze	= factory.MakeMaze();
	Room* r1	= factory.MakeRoom(1);
	Room* r2	= factory.MakeRoom(2);
	Door* theDr	= factory.MakeDoor(r1,r2);
	
	...
}

在CreateMaze只出现了MakeMaze,MakeRoom之类的接口,并没有具体Room的类型。当有新版本的NewRoom或NewDoor的时候,派生一个MazeFactory的子类NewMazeFactory(开放扩展,关闭修改原则):

class NewMazeFactory : public MazeFactory
{
public:
	NewMazeFactory();
			
	virtual Room* MakeRoom() const
	{
		return new NewRoom();
	}
	
	virtual Door* MakeDoor(Room* r1, Room* r2) const
	{
		return new NewDoor(r1, r2);
	}
	
	...
}

CreateMaze保持不变,而实际new出来的Room已经是新的NewRoom了。


但是,CreateMaze出现了一个新的东西MazeFactory。。。看看main函数的情况先

int main(void)
{
	Maze* aMaze = CreateMaze(new NewMazeFactory);
	...
}

只需要传递不同的工厂类对象,就能创建出不同的Room,Door了。每一个工厂子类都可重写相关接口,也就是说每一个子类,都可以有一套自己的实现,而这一套实现是相关联的。如MakeRoom返回NewRoom,MakeDoor返回NewDoor。这也就是“提供一个创建一系列相关或相互依赖对象的接口”。


理一下思路,例子中各元素与图中的对应关系,以及变与不变


CreateMaze:Client

MazeFactory:AbstractFactory

NewMazeFactory:ConcreteFactory1

Room:ProductA2

Door:ProductA1

main函数在图中并没有体现出来,它是作为Client的用户,是可变的(new不同的工厂出来)。Client是相对不变的,它仅依赖着MazeFactory接口。


GOF中这样说明抽象工厂的适用情况:

1.一个系统要独立于它的产品的创建、组合和表示时。(CreateMaze有自己的创建规则,它不关心具体的创建。
2.一个系统要由多个产品系列中的一个来配置时。(MazeFactory的多个接口表示一系列相关的产品
3.当你要强调一系列相关的产品对象的设计以便进行联合使用时。
4.当你提供一个产品类库,而只想显示它们的接口而不是实现时。(CreateMaze依赖MazeFactory的接口,而不是实现。


你可能感兴趣的:(设计模式-创建型-抽象工厂)