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

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

一.简介

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

二.命令模式

命令模式(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());
	}
}

六.运行结果

七.源代码下载

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

原文地址:https://www.cnblogs.com/miaowulj/p/11875414.html