- 最近在项目中需要实现快捷键功能,通过快捷键打开游戏中一些界面,经过一些参考学习,使用命令模式实现了这个功能。写这篇博客也是为了简单记录一下自己实现思路,方便以后查看
- 如果有什么地方不合理或者有错误,还请各位大佬留言指点一下,在下不胜感激
介绍
意图:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。
主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。
何时使用:在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。
如何解决:通过调用者调用接受者执行命令,顺序:调用者→接受者→命令。
关键代码:定义三个角色:1、received 真正的命令执行对象 2、Command 3、invoker 使用命令对象的入口
应用实例:struts 1 中的 action 核心控制器 ActionServlet 只有一个,相当于 Invoker,而模型层的类会随着不同的应用有不同的模型类,相当于具体的 Command。
优点: 1、降低了系统耦合度。 2、新的命令可以很容易添加到系统中去。
缺点:使用命令模式可能会导致某些系统有过多的具体命令类。
使用场景:认为是命令的地方都可以使用命令模式,比如: 1、GUI 中每一个按钮都是一条命令。 2、模拟 CMD。
注意事项:系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作,也可以考虑使用命令模式,见命令模式的扩展。
命令模式结构图
例子:使用命令模式实现游戏快捷键
按键命令基类
public abstract class CommandBase
{
// 命名的功能执行者(Receiver)
protected InputController m_Controller = null;
public CommandBase(InputController controller)
{
this.m_Controller = controller;
}
// 执行命令
public abstract void Execute();
// 撤消命令
public abstract void Undo();
}
具体的命令:背包命令(打开/关闭)
public class BagCommand : CommandBase
{
public BagCommand(InputController controller) : base(controller)
{
}
public override void Execute()
{
m_Controller.OpenKnapsack();
}
// 撤消打开背包界面的实际操作是关闭背包界面,所以在这里的进行关闭背包界面
public override void Undo()
{
m_Controller.CloseKnapsack();
}
}
命令的执行者(Receiver)
using UnityEngine;
/// <summary>
/// Receiver(功能的执行者)
/// </summary>
public class InputController
{
public void OpenKnapsack()
{
Debug.Log("打开背包");
}
public void CloseKnapsack()
{
Debug.Log("关闭背包");
}
}
命令的管理者(Invoker)
using UnityEngine;
public class InputMgr : MonoBehaviour
{
private InputController m_Controller = null;
private CommandBase m_BagCommand = null;
// 保存上一个输入的命令
private CommandBase m_LastCommand = null;
// 存储按键的数组(在实际的项目中可以实现玩家自定义快捷键)
private string[] m_Keys = new string[] { "b" };
private void Awake()
{
// 初始化
m_Controller = new InputController();
m_BagCommand = new BagCommand(m_Controller);
}
private void Update()
{
CommandBase cmd = InputHandle();
if (cmd != null)
{
/**
* 1.如果输入命令和上一个命令一样,则进行撤消操作
* 2.否则就执行新的命令,并更新lastCommand
*/
if (cmd == m_LastCommand)
{
cmd.Undo();
m_LastCommand = null;
}
else
{
cmd.Execute();
m_LastCommand = cmd;
}
}
}
private CommandBase InputHandle()
{
if (Input.GetKeyDown(m_Keys[0]))
{
return m_BagCommand;
}
// .....
return null;
}
}
- 将InputMgr挂载到一个空物体上,按B键后会在控制台输入:打开背包,再次按B键会输出关闭背包