命令模式

命令模式

定义

命令模式(Command Pattern)——是将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。

解释

正常来说,我们将一步操作分为调用方和执行方,这样二者各司其职,符合单一职责原则。

例如:将一个方块左移一步,执行方有一个Move方法,调用方传递参数并调用执行方的方法去执行。

命令模式是将调用方和执行方解藕,将:

​ 调用方——>执行方

变化为

​ 调用方——>命令——>执行方

这样,通过封装一个命令,我们解藕了调用方和执行方,并且可以保存下来命令,完成回退和复盘等等操作。

UML

在这里插入图片描述

成员

Invoker:调用方,负责命令的调用

Command:命令

Receiver:执行方,负责执行操作

ConcreteCommand:具体命令

ConcreteReceiver:具体执行者

代码

首先定义命令抽象和执行者抽象

namespace DesignModel.CommandPattern
{
	//命令抽象
	public interface ICommand  
	{
		void Excute();
	}
    //执行抽象
	public interface IReceiver  
	{
		void DoSomething();
	}
}

调用者实现

namespace DesignModel.CommandPattern
{
	public class Invoker 
	{
		ICommand command;
		public void SetCommand(ICommand command)
		{
			this.command = command;
		}

		public void Action()
		{
			command.Excute();
		}
	}
}

具体的执行者实现

namespace DesignModel.CommandPattern
{
	public class ConcreteReceiver : IReceiver 
	{
		public void DoSomething()
		{
			Debug.Log("do something !");
		}
	}
}

具体的命令实现

namespace DesignModel.CommandPattern
{
	public class ConcreteCommond : ICommand 
	{
		private IReceiver receiver;
		public ConcreteCommond(IReceiver receiver)
		{
			this.receiver = receiver;
		}
		public void Excute()
		{
			receiver.DoSomething();
		}
	}
}

客户端调用

using DesignModel.CommandPattern;

public class Client_CommandPattern_Example1 : MonoBehaviour 
{
	void Start () 
	{
		//创建一个命令的调用者(管理者)	
		Invoker invoker = new Invoker();

		//创建一个命令的执行者
		ConcreteReceiver receiver = new ConcreteReceiver();

		//创建一条命令,并传递执行者
		ICommand command = new ConcreteCommond(receiver);

		//将命令交给调用者
		invoker.SetCommand(command);

		//调用者调用命令
		invoker.Action();
	}
}
命令模式的要点
优点

1.命令模式将调用者和执行者解藕,使得调用者不需要执行者如何去执行,而只需要调用相应的命令即可;

2.命令模式将调用过程封装为命令,使得该过程可以回溯;

3.方便扩展新的命令

缺点

1.当命令很多时,每条命令都必须创建一个子类,即便是很简单的命令,增加了系统的复杂性和实现难度;

2.新增具体命令时:

​ 如果传递具体的执行者,则可能要修改具体执行者的代码,违反了开放封闭原则

​ 如果传递的是抽象的执行者,则可能要修改抽象执行者,违反了开放封闭原则

注意:

1.命令持有具体的执行者还是抽象的执行者,取决于执行者是否使用模板方法,也就是

​ 抽象:该命令适用于这一类的执行者

​ 具体:该命令适用于这一个执行者

额外的例子

用命令模式完成一个W、A、S、D让物体移动,退格键回退操作的例子

命令和执行者抽象

namespace DesignModel.CommandPattern
{
	//命令抽象,包含执行和逆执行方法
	public interface IBaseCommand  
	{
		void Execute();
		void Reexecute();
	}
    
    //执行者抽象 这里抽象不做任何事情
    public interface IBaseReceiver 
	{
	}
}

命令管理者(调用者)实现,这里保存了一个已执行的命令的队列,以及当前被填充的命令,用于执行当前命令和回退命令

namespace DesignModel.CommandPattern
{
	public class CommandManager 
	{
		private IBaseCommand currentCommand;							//当前命令
		List<IBaseCommand> doneCommands = new List<IBaseCommand>();		//已完成的命令队列

		/// <summary>
		/// 设置命令
		/// </summary>
		/// <param name="command">命令</param>
		public void SetCommand(IBaseCommand command)					
		{
			currentCommand = command;
		}

		/// <summary>
		/// 执行当前命令
		/// </summary>
		public void DoCommand()
		{
			currentCommand.Execute();
			doneCommands.Add(currentCommand);
		}

		/// <summary>
		/// 回退执行命令
		/// </summary>
		public void UnDoCommand()
		{
			IBaseCommand lastCommand;
			if (doneCommands.Count > 0)
			{
				lastCommand = doneCommands[doneCommands.Count - 1];
				lastCommand.Reexecute();
				doneCommands.Remove(lastCommand);
			}
		}
	}
}

一个具体的执行者,目前只有移动的方法

namespace DesignModel.CommandPattern
{
	public class ObjController : MonoBehaviour, IBaseReceiver
	{
		public void Move(Vector3 move)
		{
			this.transform.position += move;
		}
	}
}

移动命令

namespace DesignModel.CommandPattern
{
	public class MoveCommand : IBaseCommand 
	{
		// 一个具体的命令执行者 
		private ObjController receiver;
		private Vector3 move;
		public MoveCommand(ObjController receiver, Vector3 move)
		{
			this.receiver = receiver;
			this.move = move;
		}

		public void Execute()
		{
			Debug.Log("Move : " + move);
			receiver.Move(move);
		}

		public void Reexecute()
		{
			Debug.Log("ReMove : " + move);
			receiver.Move(-move);
		}
	}
}

一个按键监听类

public class KeyEventCtr : MonoBehaviour 
{
	public delegate void UpKeyPressHandler();
	public event UpKeyPressHandler upKeyPressEvent;

	public delegate void DownKeyPressHandler();
	public event DownKeyPressHandler downKeyPressEevent;

	public delegate void LeftKeyPressHandler();
	public event LeftKeyPressHandler leftKeyPressEvent;

	public delegate void RightKeyPressHandler();
	public event RightKeyPressHandler rightKeyPressEvent;

	public delegate void BackPressHandler();
	public event BackPressHandler backPressEvent;

	private void Update() 
	{
		if (Input.GetKeyDown(KeyCode.A))
			LeftKeyPress();
		
		if (Input.GetKeyDown(KeyCode.D))
			RightKeyPress();

		if (Input.GetKeyDown(KeyCode.W))
			UpKeyPress();
		
		if (Input.GetKeyDown(KeyCode.S))
			DownKeyPress();

		if (Input.GetKeyDown(KeyCode.Backspace))
			BackKeyPress();
	}

	public void UpKeyPress()
	{
		if (upKeyPressEvent != null)
			upKeyPressEvent();
	}

	public void DownKeyPress()
	{
		if (downKeyPressEevent != null)
			downKeyPressEevent();
	}

	public void LeftKeyPress()
	{
		if (leftKeyPressEvent != null)
			leftKeyPressEvent();
	}

	public void RightKeyPress()
	{
		if (rightKeyPressEvent != null)
			rightKeyPressEvent();
	}

	public void BackKeyPress()
	{
		if (backPressEvent != null)
			backPressEvent();
	}
}

客户端实现委托绑定

using DesignModel.CommandPattern;

public class Client_CommandPattern_MoveBox : MonoBehaviour 
{
	[SerializeField] private KeyEventCtr keyEventCtr;
	[SerializeField] private ObjController receiver;

	private CommandManager commandManager;
	private void Start() 
	{
		//一个管理者
		commandManager = new CommandManager();
		
		//添加事件监听
		keyEventCtr.upKeyPressEvent += MoveUp;
		keyEventCtr.downKeyPressEevent += MoveDown;
		keyEventCtr.leftKeyPressEvent += MoveLeft;
		keyEventCtr.rightKeyPressEvent += MoveRight;

		keyEventCtr.backPressEvent += ReMove;
	}

	private void MoveUp()
	{
		commandManager.SetCommand(new MoveCommand(receiver, new Vector3(0, 1, 0)));
		commandManager.DoCommand();
	}

	private void MoveDown()
	{
		commandManager.SetCommand(new MoveCommand(receiver, new Vector3(0, -1, 0)));
		commandManager.DoCommand();
	}

	private void MoveRight()
	{
		commandManager.SetCommand(new MoveCommand(receiver, new Vector3(1, 0, 0)));
		commandManager.DoCommand();
	}

	private void MoveLeft()
	{
		commandManager.SetCommand(new MoveCommand(receiver, new Vector3(-1, 0, 0)));
		commandManager.DoCommand();
	}

	private void ReMove()
	{
		commandManager.UnDoCommand();
	}
}

结果展示

有时间就把例子传到github上去

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值