从王者荣耀看设计模式(九.命令模式)

Posted miaowulj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从王者荣耀看设计模式(九.命令模式)相关的知识,希望对你有一定的参考价值。

从王者荣耀看设计模式(命令模式)

技术图片

一.简介

王者荣耀是一款团队竞技游戏。良好的团队信息交流在一定程度上能帮助队伍取得胜利。为了保证游戏的流畅性与便捷性,王者荣耀提供了快捷交流机制,在王者小地图旁边有几个快捷聊天按钮(开始撤退,发起进攻,请求结合),玩家可通过点击快捷聊天按钮发出相应命令与队友进行交流

二.命令模式

命令模式(Command Pattern):命令模式是一种高内聚的模式,将"请求"封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。

  • 命令模式的使用场景
    1. 只要你认为是命令的地方就可以采用命令模式,例如,在GUI开发中,一个按钮的点击就是一个命令,可以采用命令模式;模拟DOS命令的时候,当然也要采用命令模式:触发-反馈机制的处理等。
    2. 解决命令的请求者和命令的实现者之间的耦合关系。
  • 命令模式涉及的设计原则有:
  1. 每一个命令都是一个操作:请求的一方发出请求,要求执行一个操作;接收的一方收到请求,并执行操作。
  2. 请求方和接收方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。
  3. 命令模式的关键在于引入了抽象命令接口,且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。
  • 命令模式的通用类图:
    技术图片

  • 命令模式所涉及的角色有:
    抽象命令(Command):定义命令的接口,声明执行的方法。
    具体命令(ConcreteCommand):具体命令,实现要执行的方法,它通常是“虚”的实现;通常会有接收者,并调用接收者的功能来完成命令要执行的操作。
    接收者(Receiver):真正执行命令的对象。任何类都可能成为一个接收者,只要能实现命令要求实现的相应功能。
    调用者(Invoker):要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
    客户端(Client):命令由客户端来创建,并设置命令的接收者。
    ---

  • 命令模式的优点:
    1. 类间解耦:调用者角色与接受者角色之间没有任何依赖关系,调用者实现功能时只需调用Command抽象类的execute方法就可以,不需要了解到底是哪个接收者执行
    2. 可扩展性:Command的子类可以非常容易地扩展,而调用者Invoker和高层次的模块Client不产生严重的代码耦合。
    3. 命令模式结合其他模式会更优秀:命令模式可以结合责任链模式,实现命令族解析任务;结合模板方法模式,则可以减少Command子类的膨胀问题。
  • 命令模式的缺点:
    命令模式也是优缺点的,请看Command子类:如果有N个命令,问题就出来了,Command的子类就可不是几个,而是N个,这个类膨胀得非常大

三.结构图

技术图片

四.设计类图

技术图片

五.代码实现

com.practice.ObserverModule包内容结合自从王者荣耀看设计模式(观察者模式)
Observerable(抽象被观察者接口)

package com.practice.ObserverModule;
/***
 * 抽象被观察者接口
 * 声明了添加、删除、通知观察者方法
 *
 */

public interface Observerable {
    public void RegisterObserver(Observer o);
    public void RemoveObserver(Observer o);
    public void NotifyObserver();
}

InformMessage类(被观察者类)

package com.practice.ObserverModule;

import java.util.ArrayList;
import java.util.List;

/*
 * 被观察者
*实现了Observerable接口,对Observerable接口的三个方法进行了具体实现
 *
 */
public class InformMessage implements Observerable {
    private String message;
    private String heroName;
    private List<Observer> list;
    
    public InformMessage() {
        list = new ArrayList<Observer>();
    }
    
    public void NotifyObserver() {
        for(int i = 0;i < list.size(); i++) {
            Observer observer = list.get(i);
            observer.update(message);
        }
    }

    public void RegisterObserver(Observer o) {
        list.add(o);
        
    }

    public void RemoveObserver(Observer o) {
        if(!list.isEmpty())
            list.remove(o);
    }

    public void setInformation(String name,Observer o,String message) {
        this.message = message;
        this.heroName = name;
        System.out.println("英雄[" + heroName + "]发出消息:" + message);
        RemoveObserver(o);
        NotifyObserver();
        list.add(o);
    }
}

Observer类(抽象观察者类)

package com.practice.ObserverModule;

/*
 * 抽象观察者
 * 定义了一个update()方法,当被观察者调用notifyObservers()方法时,观察者的update()方法会被回调。
 */

public interface Observer {
    public void update(String message);
}

Hero类(观察者类)

package com.practice.ObserverModule;
/**
 * 观察者
 * 实现了update方法
 *
 */
public class Hero implements Observer{
    private String name;
    private String message;
    
    public Hero(String heroName) {
        this.name = heroName;
    }
    
    public void update(String message) {
        this.message = message;
        read();
    }
    
    public void read() {
        System.out.println(name + "收到消息:" + message);
    }
}

GameInform类(接收类)

package com.practice.OrderModule;

/*
 * 接收类
 */

public class GameInform {
    public String Attack() {
        return "发起进攻";
    }
    
    public String Retreat() {
        return "开始撤退";
    }
    
    public String Gather() {
        return "请求集合";
    }
}

Command类(抽象命令角色类)

package com.practice.OrderModule;

/*
 * 抽象命令角色类
 */

public interface Command {
    public String execute();
}

AttackCommand类(具体角色类)

package com.practice.OrderModule;

/*
 * 具体角色类
 */

public class AttackCommand implements Command{
    private GameInform gameInform;
    
    public AttackCommand(GameInform gameInform) {
        this.gameInform = gameInform;
    }
    
    public String execute() {
        return gameInform.Attack();
    }
}

RetreatCommand类(具体角色类)

package com.practice.OrderModule;

/*
 * 具体角色类
 */

public class RetreatCommand implements Command{
    private GameInform gameInform;
    
    public RetreatCommand(GameInform gameInform) {
        this.gameInform = gameInform;
    }
    
    public String execute() {
        return gameInform.Retreat();
    }

}

GatherCommand类(具体角色类)

package com.practice.OrderModule;

/*
 * 具体角色类
 */

public class GatherCommand implements Command{
    private GameInform gameInform;
    
    public GatherCommand(GameInform gameInform) {
        this.gameInform = gameInform;
    }
    
    public String execute() {
        return gameInform.Gather();
    }
}

Keypad类(请求角色类)

package com.practice.OrderModule;

/*
 * 请求角色类
 */

public class Keypad {
    private Command AttackCommand;
    private Command RetreatCommand;
    private Command GatherCommand;
    
    public void setAttackCommand(Command AttackCommand) {
        this.AttackCommand = AttackCommand;
    }
    
    public void setRetreatCommand(Command RetreatCommand) {
        this.RetreatCommand = RetreatCommand;
    }
    
    public void setGatherCommand(Command GatherCommand) {
        this.GatherCommand = GatherCommand;
    }
    
    public String Attack() {
        return AttackCommand.execute();
    }
    
    public String Retreat() {
        return RetreatCommand.execute();
    }
    
    public String Gather() {
        return GatherCommand.execute();
    }
}

Test类(测试类)

package com.practice.Test;

import com.practice.ObserverModule.Hero;
import com.practice.ObserverModule.InformMessage;
import com.practice.ObserverModule.Observer;
import com.practice.OrderModule.AttackCommand;
import com.practice.OrderModule.Command;
import com.practice.OrderModule.GameInform;
import com.practice.OrderModule.GatherCommand;
import com.practice.OrderModule.Keypad;
import com.practice.OrderModule.RetreatCommand;

public class Test {
    public static void main(String [] args) {
        //首先创建被观察者对象
        InformMessage HeroGlory = new InformMessage();
        //创建接收者对象
        GameInform gameInform = new GameInform();
        
        //将接收者对象传入命令对象
        Command attackCommand = new AttackCommand(gameInform);
        Command retreatCommand = new RetreatCommand(gameInform);
        Command gatherCommand = new GatherCommand(gameInform);
        
        //创建请求者对象
        Keypad keypad = new Keypad();
        //把命令传给请求者
        keypad.setAttackCommand(attackCommand);
        keypad.setRetreatCommand(retreatCommand);
        keypad.setGatherCommand(gatherCommand);
        
        //创建观察者对象
        Observer HanXin = new Hero("韩信");
        Observer HouYi = new Hero("后羿");
        Observer DianWei = new Hero("典韦");
        Observer DaJi = new Hero("妲己");
        Observer LiuShan = new Hero("刘禅");
        
        //添加观察者
        HeroGlory.RegisterObserver(HanXin);
        HeroGlory.RegisterObserver(HouYi);
        HeroGlory.RegisterObserver(DianWei);
        HeroGlory.RegisterObserver(DaJi);
        HeroGlory.RegisterObserver(LiuShan);
        
        //1.更新消息 2.调用请求
        HeroGlory.setInformation("妲己",DaJi,keypad.Retreat());
        
        System.out.println("---------------------------------------------------");
        HeroGlory.setInformation("后羿",HouYi,keypad.Gather());
    }
}

运行结果
技术图片

以上是关于从王者荣耀看设计模式(九.命令模式)的主要内容,如果未能解决你的问题,请参考以下文章

从王者荣耀看设计模式(十四.工厂方法模式)

从王者荣耀看设计模式(八.装饰者模式)

从王者荣耀看设计模式(十七.原型模式)

从王者荣耀看设计模式(保护代理模式)

从王者荣耀看设计模式(十六.建造者模式)

从王者荣耀看设计模式(十.适配器模式)