设计模式 - 抽象工厂 - BombedMazeFactory
Design Patterns - Abstract Factory - BombedMazeFactory
我对《设计模式》一书中的抽象工厂模式示例代码有疑问。
这本书展示了迷宫游戏的一个简化的部分示例,其中有墙和门连接房间。
有一个基本的 MazeFactory class,它具有以下工厂方法:
class MazeFactory {
public:
MazeFactory();
virtual Maze* MakeMaze() const { return new Maze; }
virtual Wall* MakeWall() const { return new Wall; }
virtual Room* MakeRoom(int n) const { return new Room(n); }
virtual Door* MakeDoor(Room* r1, Room* r2) const {
return new Door(r1, r2);
}
}
作者然后定义了 MazeFactory 的特化:
class BombedMazeFactory : public MazeFactory {
BombedMazeFactory();
virtual Room* MakeWall() const { return new BombedWall; }
virtual Door* MakeRoom(int n) const { return new RoomWithABomb(n); }
};
我不太清楚 RoomWithABomb 应该如何工作,但可以说它创建了一个有 5% 几率包含炸弹的房间,如果你打开一扇包含炸弹房间的门,你就会爆炸。
现在假设客户使用 BombedMazeFactory class 创建了他们的迷宫,并且他们创建了一些房间。创建的房间类型为 RoomWithABomb*,但是工厂 returns a Room*.
为了实现一些迷宫游戏逻辑,我假设您需要检查一个房间是否包含炸弹,但 Room* 对炸弹一无所知。我们可以找出房间是否包含炸弹的唯一方法是将 Room* 转换为 RoomWithABomb*,这是不好的做法吗?
他们的示例是否经过深思熟虑,或者是否有其他处理此类情况的方法?
这里的答案是你不需要知道它是什么样的房间。
假设 Room
是一个带有方法 enter()
的 class,当你进入房间时,它可能会打印出一些东西。 class 可能看起来像这样(我将在 Java 中这样做,因为我对 C++ 不太熟悉,但你会明白的):
public class Room {
protected int roomNumber;
public Room(int n) {
roomNumber = n;
}
public void enter() {
System.out.println("You entered room number " + roomNumber);
}
public void getRoomNumber() {
return roomNumber;
}
}
现在让我们考虑一个有炸弹的房间。显然它是 Room
的派生词,但它应该打印出类似 "You exploded" 的内容。
public class RoomWithABomb extends Room {
public RoomWithABomb(int n) {
super(n);
}
public void enter() {
System.out.println("Oh no! There was a bomb in the room! You died");
}
}
所以现在我们的 RoomWithABomb
class 覆盖了 Room
class 的行为(多态性!)。然而,调用者不需要确切知道进入的房间类型,因为我们知道每个 Room
(因此每个 RoomWithABomb
,因为它继承自 Room
)都有一个enter()
方法。
那么抽象工厂的用意是什么?我们想创建相似的对象,继承自一个共同的 superclass 或接口的对象,这样其他对象就不需要知道如何创建它们。通过这样做,我们还将其他对象与所述接口的具体实现分离(迷宫甚至不知道房间里有炸弹)。
我对《设计模式》一书中的抽象工厂模式示例代码有疑问。
这本书展示了迷宫游戏的一个简化的部分示例,其中有墙和门连接房间。
有一个基本的 MazeFactory class,它具有以下工厂方法:
class MazeFactory {
public:
MazeFactory();
virtual Maze* MakeMaze() const { return new Maze; }
virtual Wall* MakeWall() const { return new Wall; }
virtual Room* MakeRoom(int n) const { return new Room(n); }
virtual Door* MakeDoor(Room* r1, Room* r2) const {
return new Door(r1, r2);
}
}
作者然后定义了 MazeFactory 的特化:
class BombedMazeFactory : public MazeFactory {
BombedMazeFactory();
virtual Room* MakeWall() const { return new BombedWall; }
virtual Door* MakeRoom(int n) const { return new RoomWithABomb(n); }
};
我不太清楚 RoomWithABomb 应该如何工作,但可以说它创建了一个有 5% 几率包含炸弹的房间,如果你打开一扇包含炸弹房间的门,你就会爆炸。
现在假设客户使用 BombedMazeFactory class 创建了他们的迷宫,并且他们创建了一些房间。创建的房间类型为 RoomWithABomb*,但是工厂 returns a Room*.
为了实现一些迷宫游戏逻辑,我假设您需要检查一个房间是否包含炸弹,但 Room* 对炸弹一无所知。我们可以找出房间是否包含炸弹的唯一方法是将 Room* 转换为 RoomWithABomb*,这是不好的做法吗?
他们的示例是否经过深思熟虑,或者是否有其他处理此类情况的方法?
这里的答案是你不需要知道它是什么样的房间。
假设 Room
是一个带有方法 enter()
的 class,当你进入房间时,它可能会打印出一些东西。 class 可能看起来像这样(我将在 Java 中这样做,因为我对 C++ 不太熟悉,但你会明白的):
public class Room {
protected int roomNumber;
public Room(int n) {
roomNumber = n;
}
public void enter() {
System.out.println("You entered room number " + roomNumber);
}
public void getRoomNumber() {
return roomNumber;
}
}
现在让我们考虑一个有炸弹的房间。显然它是 Room
的派生词,但它应该打印出类似 "You exploded" 的内容。
public class RoomWithABomb extends Room {
public RoomWithABomb(int n) {
super(n);
}
public void enter() {
System.out.println("Oh no! There was a bomb in the room! You died");
}
}
所以现在我们的 RoomWithABomb
class 覆盖了 Room
class 的行为(多态性!)。然而,调用者不需要确切知道进入的房间类型,因为我们知道每个 Room
(因此每个 RoomWithABomb
,因为它继承自 Room
)都有一个enter()
方法。
那么抽象工厂的用意是什么?我们想创建相似的对象,继承自一个共同的 superclass 或接口的对象,这样其他对象就不需要知道如何创建它们。通过这样做,我们还将其他对象与所述接口的具体实现分离(迷宫甚至不知道房间里有炸弹)。