2017-02-15 4 views
0

У меня есть вопрос относительно образца образца шаблона Abstract Factory из книги Design Patterns.Дизайн шаблонов - Абстрактная фабрика - BombedMazeFactory

В книге представлен упрощенный и частичный пример игры в лабиринт, где есть стены и двери, соединяющие комнаты.

Существует базовый класс MazeFactory, который имеет следующие фабричные методы:

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, и они создают некоторые комнаты. Созданные комнаты имеют тип RoomWithABomb *, однако завод возвращает комнату *.

Чтобы реализовать логику игры в лабиринте, я бы предположил, что вам нужно будет проверить, содержит ли в комнате бомбу, но Room * не знает о бомбах. Единственный способ узнать, есть ли в комнате бомба, - это отличить комнату * от RoomWithABomb *, что плохой практикой?

Является ли их пример не очень хорошо продуманным или существует какой-либо другой способ обработки таких случаев?

+0

Если в каждой комнате был метод Enter(), это может быть переопределено в подклассе RoomWithABomb и иметь логику случайного включения бомбы. – dbugger

ответ

0

Ответ здесь: вам не нужно знать, что это за комната. Скажем, Room - это класс со способом enter(), и когда вы входите в комнату, возможно, он что-то распечатывает. Класс может выглядеть следующим образом (я буду делать это в 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, но она должна напечатать что-то вроде «Вы взорвались».

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 класс переопределяет поведение от Room класса (полиморфизм!). Однако вызывающему абоненту не нужно было точно знать, в какую комнату вводится, потому что мы знаем, что каждый Room (и, следовательно, также каждый RoomWithABomb, так как он наследует от Room), имеет метод enter().

Итак, в чем цель абстрактной фабрики? Мы хотим создать похожие объекты, объекты, которые наследуются от обычного суперкласса или интерфейса, так что другим объектам не нужно знать, как их создавать. Делая это, мы также отделяем другие объекты от конкретных реализаций интерфейса (Лабиринт даже не знает, что есть комната с бомбой).

+0

Я доволен этим ответом. Я предполагаю, что enter() понадобится экземпляр MazeGame для изменения состояния игры, что увеличивает сцепление, но я не вижу хорошей альтернативы. – mrpringle

Смежные вопросы