Java设计模式之从[使命召唤等游戏的任务提示]分析职责链(Chain Of Responsibility)模式

来源:互联网 发布:js 层叠式图片轮播 编辑:程序博客网 时间:2024/06/11 02:45

  我们在使命召唤、暗黑破坏神等游戏时,总会接到各种各样的游戏任务,如到某某地方解救某人,或者消灭某某地方的敌人等。当玩家进入到某一个地图(以下称之为游戏场景)时,我们就可以查看它的任务提示。在这个机制下,我们认为,所有的游戏场景都继承于一个类(如HelpHandler),这个类包含一个显示任务提示的方法(如showHelp)。问题在于,任务的提示是有“上下文联系的”,任务的提示是和你的“场景是如何移动的”有关。例如,场景A中没有任务提示,场景B中没有任务提示,场景C、D中分别有任务提示MessageC和MessageD,如果我们从C->B->A移动,那么我们查看的任务提示就是MessageC,如果我们从D->B->A,那么任务提示就是MessageD。我们可以这样来设计:A、B、C、D这4个场景都继承于同一个类(如HelpHandler),因此它们都有显示任务提示的showHelp方法。它们内部有对另外的一个HelpHandler对象的引用,我们称之为候选者,如果自身无法处理任务提示,则调用候选者的showHelp方法。如果看到这里不大明白,就请看下图、示例和我下面的解释:

  以上就是我刚刚谈到的职责链模式。它的意图是使得对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。用直白一点的话说就是,如果我可以处理这个请求则处理之,如果不能处理,则让我的候选者来处理。

  以下是职责链模式的Java示例代码:

interface Helpful {void help();}abstract class HelpHandler {HelpHandler successor;Helpful help;    public HelpHandler(){}    public void setHandler(HelpHandler parent, Helpful help){        this.successor = parent;        this.help = help;    }    public void showHelp(){        if (hasHelp()){            help.help();        } else {            if (successor != null) successor.showHelp();        }    }    private boolean hasHelp(){        return help != null;    }}class World extends HelpHandler {    public World(HelpHandler parent) {        Helpful help = new Helpful (){            public void help() {                System.out.println("大地图任务: 请按W、S、A、D来移动。");            }        };        setHandler(parent, help);    }}class House extends HelpHandler {    public House(HelpHandler parent) {        Helpful help = new Helpful (){            public void help() {                System.out.println("房间任务: 请拿起房间的武器出门。");            }        };        setHandler(parent, help);    }}class Cave extends HelpHandler {    public Cave(HelpHandler parent) {        Helpful help = new Helpful (){            public void help() {                System.out.println("洞穴任务: 请消灭洞穴中的所有怪兽。");            }        };        setHandler(parent, help);    }}class Island extends HelpHandler {    public Island(HelpHandler parent) {        setHandler(parent, null);    }}public class Responsibility {    public static void main(String[] args) {        World world = new World(null);        House house = new House(world);        Cave cave = new Cave(world);        Island island = new Island(world);        Island islandWithCave = new Island(cave);        world.showHelp();        house.showHelp();        cave.showHelp();        island.showHelp();        islandWithCave.showHelp();    }}


  简要分析上面的代码。上述代码是模拟在游戏的不同场景下显示任务提示。所有的场景都继承于HelpHandler类,HelpHandler类中有个HelpHandler类型的引用successor,表示处理方法的候选者。我们看看HelpHandler中的showHelp方法,它首先判断本类是否能够显示任务提示(即hasHelp是否返回true),如果可以显示则显示之,不能显示,则调用候选者的showHelp方法。通过这种方法,可以使HelpHandler类连成“链状”。

  值得注意的是,我们需要在HelpHandler派生类中构造一个匿名类,这个匿名类继承于Helpful接口,这个是显示任务提示的一个接口。在不同的派生类中,我们构造不同的Helpful接口的对象来实现显示不同的任务提示,这其实是一种策略(Strategy)模式(以后会提到)。

  再看看main方法,我们定义的World、House、Cave类都有自己的任务提示,而Island类没有,所以它的任务提示取决于它的候选者,因此,island的任务提示就是其候选者world的任务提示,islandWithCave的任务提示就是其候选者cave的任务提示,因此程序的结果为:

大地图任务: 请按W、S、A、D来移动。
房间任务: 请拿起房间的武器出门。
洞穴任务: 请消灭洞穴中的所有怪兽。
大地图任务: 请按W、S、A、D来移动。
洞穴任务: 请消灭洞穴中的所有怪兽。

  职责链的有点是降低了发送请求者和接受请求者的耦合度,增强了指派职责的灵活性,它只需要指定一个候选者即可实现职责的指派。然而,它的缺点是,无法保证指派的职责一定能被接收,由于含有递归思想,这个模式会有一定的性能损耗,如果不注意可能会陷入循环调用之中。

0 0
原创粉丝点击