(资料图片)

注:所有知识来源于《设计模式:可复用软件面向对象的基础》

创建型设计模式抽象了实例化过程,它们帮助一个系统独立于如何创建、组合和表示它的那些对象。一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象。在这些模式中有两个不断出现的主旋律:

整个系统关于这些对象所知道的是由抽象类所定义的接口。

示例—创建迷宫

我们以为游戏创建一个迷宫作为学习创建型模式的例子,忽略迷宫中的许多细节以及一个迷宫游戏中有多少游戏者,仅关注迷宫是怎么创建的。我们将一个迷宫定义为一系列房间,一个房间知道它的邻居:可能的邻居要么是另一个房间,要么是一堵墙或者是到另一个房间的一扇门。在该例子中,需要使用到的作为迷宫构件的类有Room、Door和Wall,注意我们只关注怎样创建迷宫,忽略游戏者、显示操作和在迷宫中四处移动等操作,以及其他一些重要的却与创建迷宫无关的功能。

图1 迷宫构件的类图

public enum Direction {    NORTH,    SOUTH,    EAST,    West}
public abstract class MapSite {    public abstract void enter();}
public class Room extends MapSite {    private int roomNumber;    private Map sites;    public Room(int roomNumber) {        this.roomNumber = roomNumber;        this.sites = new HashMap<>(4);    }    public MapSite getSide(Direction direction) {        return sites.get(direction.getDirection());    }    public void setSites(Direction direction, MapSite mapSite) {        sites.put(direction.getDirection(), mapSite);    }    public int getRoomNumber() {        return this.roomNumber;    }    @Override    public void enter() {        System.out.println("Enter another room and position change.");    }}
public class Wall extends MapSite {    @Override    public void enter() {        System.out.println("It"s a wall. Position not change.");    }}
public class Door extends MapSite {    private Room room1;    private Room room2;    boolean isOpen;    public Door(Room room1, Room room2, boolean isOpen) {        this.room1 = room1;        this.room2 = room2;        this.isOpen = isOpen;    }    @Override    public void enter() {        if (isOpen) {            System.out.println("The door is opened. Enter another room and position change.");        } else {            System.out.println("The door is closed. Position not change.");        }    }}
public class Maze {    Map rooms = new HashMap<>();    public void addRoom(Room room) {        rooms.put(room.getRoomNumber(), room);    }    public Room getRoom(int roomNumber) {        return rooms.get(roomNumber);    }}
public class MazeGame {    public Maze createMaze() {        Maze maze = new Maze();        Room room1 = new Room(1);        Room room2 = new Room(2);        Door door = new Door(room1, room2, true);        maze.addRoom(room1);        maze.addRoom(room2);        room1.setSites(Direction.NORTH, new Wall());        room1.setSites(Direction.SOUTH, new Wall());        room1.setSites(Direction.EAST, door);        room1.setSites(Direction.West, new Wall());        room2.setSites(Direction.NORTH, new Wall());        room2.setSites(Direction.SOUTH, new Wall());        room2.setSites(Direction.EAST, new Wall());        room2.setSites(Direction.West, door);        return maze;    }}

考虑到这创建的是一个只有两个房间的迷宫就已经显得相当复杂了,虽然可以提前在Room构造器里用墙壁初始化房间的每一面,但是这只是把代码移到了其它地方。这个方法真正的问题不在于它的大小而在于它不灵活,它对迷宫的布局进行硬编码。改变布局意味着改变这个成员方法,通过以下方式定义:重定义(override)它——意味着重新实现整个过程;对它的部分进行改变——容易产生错误并且不利于复用。这种情况下改变的最大障碍是对以实例化的类进行硬编码,创建型模式就提供了多种不同的方法,从实例化它们的代码中去除对这些具体类的显示引用。

剩下的Singleton模式可以保证每个游戏中仅有一个迷宫而且所有的游戏对象都可以迅速访问它——不需要求助于全局变量或方法。Singleton也使得迷宫易于扩展或替换且不需要变动已有的代码。

推荐内容