设计模式-命令模式

命令模式

       原理:将一个请求封装成一个对象,从而允许你使用不同的请求、队列或日志将客户端参数化。同时支持请求操作的撤销与恢复。命令就是面向对象化的回调。亦可理解为“后悔药”
       作用 :“撤销”与”再做”最常见的便是用在输入控制上。我们可以将输入的信号转换成对应的指令,存入命令队列中,依次执行。多用于 服务器与客户端的开发
       例:红警(红色警戒)中训练美国大兵的命令、当点击时,开始倒计时产生大兵,再次点击时,显示数字“2”,表示要训练两个大兵也就是第二个命令被暂存当右键点击时,命令还可以撤销,数字由“2”变为了“1”,也就是第二个命令被撤销了
       如果当用户删掉了某一个物体,下一刻他要执行撤销时,会发现那个物体的对象已不存在,这样的话撤销操作就会出现找不到对象的问题,所以根据克隆对象的方式,当用户删掉物体再还原时,我们并非还原他原本的那个物体,而是根据操作记录里面记载的对象删除前的属性重新克隆一个物体。

(1)第一种实现原理:
首先定义一个所有命令的父类( CommandBase)、有且仅有两个操作,但是只在父类中进行描述、在子类中进行实现、因为有的命令是不一样的

  • 执行命令
  • 撤销命令
//==========================
// - FileName:      BaseCommand.cs         
// - Created:       true.	
// - CreateTime:    2020/02/27 23:10:01	
// - Email:         1670328571@qq.com		
// - Region:        China WUHAN	
// - Description:   执行以及撤销
//==========================
public class BaseCommand : object
{
    //命令描述
    private string _commandDescribe;
    public string CommandDescribe
    {
        set {
            _commandDescribe = value;
        }
        get {
            return _commandDescribe;
        }
    }
 
    //执行命令
    public virtual void ExecuteCommand()
    {
    }
 
    //撤销命令
    public virtual void RevocationCommand()
    {
    }
}

针对不同的对象,定制各自的命令类****这里我暂时只针对UGUI的InputField和角色Player进行命令收集,通过命令收集者来监听对象的一举一动,记录每一条命令的属性,比如InputField的操作,我们需要的属性也就只有一个,那就是InputField的输入值,所以将之纳为命令的收集目标即可。

//==========================
// - FileName:      InputFieldCommand.cs         
// - Created:       true.	
// - CreateTime:    2020/02/27 23:10:01	
// - Email:         1670328571@qq.com		
// - Region:        China WUHAN	
// - Description:   具体实现
//==========================
using UnityEngine.UI;
/// <summary>
/// InputField操作的命令
/// </summary>
public class InputFieldCommand : BaseCommand
{
    #region 命令操作、撤销所涉及到的属性
    //目标
    private InputField _commandTarget;
    //目标的值
    private string _commandValue;
    #endregion
 
    public InputFieldCommand(InputField commandTarget, string commandValue, string commandDescribe)
    {
        _commandTarget = commandTarget;
        _commandValue = commandValue;
        CommandDescribe = commandDescribe;
    }
 
    /// <summary>
    /// 执行命令
    /// </summary>
    public override void ExecuteCommand()
    {
        base.ExecuteCommand();
 
        _commandTarget.text = _commandValue;
    }
 
    /// <summary>
    /// 撤销命令
    /// </summary>
    public override void RevocationCommand()
    {
        base.RevocationCommand();
 
        _commandTarget.text = _commandValue;
    }
}

我暂时只记录他的移动命令,也就是说只有一个移动位置的属性需要被命令收集者监测。

//==========================
// - FileName:      PlayerCommand.cs         
// - Created:       true.	
// - CreateTime:    2020/02/27 23:10:01	
// - Email:         1670328571@qq.com		
// - Region:        China WUHAN	
// - Description:   主角命令
//==========================
using UnityEngine;
public class PlayerCommand : BaseCommand
{
    #region 命令操作、撤销所涉及到的属性
    //目标
    private Player _commandTarget;
    //目标的位置
    private Vector3 _commandPosition;
    #endregion
 
    public PlayerCommand(Player commandTarget, Vector3 commandPosition, string commandDescribe)
    {
        _commandTarget = commandTarget;
        _commandPosition = commandPosition;
        CommandDescribe = commandDescribe;
    }
 
    /// <summary>
    /// 执行命令
    /// </summary>
    public override void ExecuteCommand()
    {
        base.ExecuteCommand();
 
        _commandTarget.transform.position = _commandPosition;
    }
 
    /// <summary>
    /// 撤销命令
    /// </summary>
    public override void RevocationCommand()
    {
        base.RevocationCommand();
 
        _commandTarget.transform.position = _commandPosition;
    }
}

命令收集者

//==========================
// - FileName:      CommandManager.cs         
// - Created:       true.	
// - CreateTime:    2020/02/27 23:10:01	
// - Email:         1670328571@qq.com		
// - Region:        China WUHAN	
// - Description:   命令收集
//==========================
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 命令收集者
/// </summary>
public class CommandManager 
{
    /// 命令集
	private List<BaseCommand> CommandSet;
 
    public CommandManager()
    {
        CommandSet = new List<BaseCommand>();
    }
 
    /// <summary>
    /// 执行新的命令
    /// </summary>
    public void ExecutiveCommand(BaseCommand command)
    {
        CommandSet.Add(command);
        command.ExecuteCommand();
 
        Debug.Log("执行命令:" + command.CommandDescribe);
    }
 
    /// <summary>
    /// 撤销上一个命令
    /// </summary>
    public void RevocationCommand()
    {
        if (CommandSet.Count > 0)
        {
            BaseCommand command = CommandSet[CommandSet.Count - 1];
            CommandSet.Remove(command);
            command.RevocationCommand();
            
            Debug.Log("撤销命令:" + command.CommandDescribe);
        }
    }
}

角色类

//==========================
// - FileName:      Player .cs         
// - Created:       true.	
// - CreateTime:    2020/02/27 23:10:01	
// - Email:         1670328571@qq.com		
// - Region:        China WUHAN	
// - Description:   角色类
//==========================
using UnityEngine;
 
public class Player : MonoBehaviour 
{
    //角色移动事件
    public delegate void MoveDelegate(Vector3 pos);
    public event MoveDelegate MoveEvent;
 
    /// <summary>
    /// 角色移动
    /// </summary>
    public void Move(Vector3 pos)
    {
        if (MoveEvent != null)
            MoveEvent(pos);
    }
}

测试脚本

//==========================
// - FileName:      CommandModeTest.cs         
// - Created:       true.	
// - CreateTime:    2020/02/27 23:10:01	
// - Email:         1670328571@qq.com		
// - Region:        China WUHAN	
// - Description:   测试
//==========================
using UnityEngine;
using UnityEngine.UI;
 
public class CommandModeTest : MonoBehaviour 
{
    public Camera MainCamera;
    public GameObject UIPanel;
 
    public InputField userName;
    public InputField passWord;
    public Player player;
    
    private CommandManager _commandManager;
 
    private void Awake()
	{
        Init();
    }
 
    private void Init()
    {
        //定义一个命令收集者
        _commandManager = new CommandManager();
 
        //命令收集者:监听userName的值改变操作
        userName.onEndEdit.AddListener((string value) =>
        {
            _commandManager.ExecutiveCommand(new InputFieldCommand(userName, value, "修改用户名输入框的值为 " + value));
        });
 
        //命令收集者:监听passWord的值改变操作
        passWord.onEndEdit.AddListener((string value) =>
        {
            _commandManager.ExecutiveCommand(new InputFieldCommand(passWord, value, "修改密码输入框的值为 " + value));
        });
 
        //命令收集者:监听player的移动操作
        player.MoveEvent += (Vector3 pos) =>
        {
            _commandManager.ExecutiveCommand(new PlayerCommand(player, pos, "角色移动到 " + pos));
        };
    }
}

定义一个命令收集者,并对场景中的两个InputField输入框和Player进行操作监听,当目标处在被监听中的事件发生时,记录此时需要记录的属性,并存入命令集。然后我们做一个点击地面让角色移动的简易例子,以便于我们测试。


/// <summary>
    /// 点击地面移动角色
    /// </summary>
    private void PlayerMove()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = MainCamera.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit) && hit.transform.name == "Root")
            {
                player.Move(hit.point);
            }
        }
    }
    /// <summary>
    /// 撤销操作
    /// </summary>
    private void RevocationCommand()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            _commandManager.RevocationCommand();
        }
    }

综上所述,命令模式的本质其实就是记录每一步操作为一个可再次访问的对象,当然一般为了解耦合,标准命令模式会将命令的触发者和调用者都分开处理,也就是说一方面只管触发新的命令,另一方面只管将命令分发给他的调用者执行,实现一种高强度的松耦合形式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值