当前位置:网站首页>命令模式 - Unity
命令模式 - Unity
2022-07-07 15:38:00 【有趣就行】
命令模式
命令模式是对象行为型模式,通过将请求者和执行者之间的请求抽离出来封装成一个对象,从而使发出请求的职责和执行请求的职责分离。请求者和执行者通过命令对象来进行沟通,这样使得对命令对象进行存储,管理,传递等。
命令模式是行为型模式中十分常用的模式,在游戏开发中也十分重要。通过将大量的命令进行管理和存储,保证了命令的顺序和统一。在使用软件时,我们经常会用到撤销这个操作,软件是如何执行撤销的,显然是将你的每一步操作进行保存,通过读取每步操作进行还原。而这就是命令模式,其中每步操作就是一个命令。
例如,遥控器和电视机,遥控器是请求者,电视机是执行者,谁是命令呢,遥控器上的按钮就是命令。餐厅中一般会有一个菜单供顾客选择,服务员进行将菜单转递给厨师,厨师负责烧菜。其中菜单中选择的菜就是一个命令,服务员作为中间人(属于调用者),他不负责执行,负责传递和管理这些菜单(命令),而菜单最后会被厨师拿到,并开始执行任务(厨师就是执行者)。多么生动形象,这就是生活里的智慧。
结构
说明
- 抽象命令(Command) - 一般只有一个执行命令方法的接口(也可以有撤销方法,当然如果需要的话)
- 具体命令 (Concrete Command)- 抽象命令的具体实现类,本身不实现方法,作为实现者参数的载体,将工作委托给实现者。
- 实现者(Receiver)- 实现业务逻辑的类,是最终完成方法的类,几乎所有对象都可以作为实现者。
- 调用者(Invoker)- 有储存多个命令对象,不直接访问实现者,通过命令对象执行请求。(本身即不创建命令对象,也不执行业务方法),主要是对命令对象的管理,储存,执行等。
实现
这个例子可能比较繁琐,但大体并没有太复杂。
主要是实现 恢复 和 撤销 等功能。
通过命令驱动UI移动
移动枚举
public enum MoveDirection
{
Left,
Right,
Up,
Down,
}
UI 移动 - 实现者(单例模式,只需要一份即可)
public class UIMove
{
private static UIMove _instacne = new UIMove();
//移动距离
private const float MoveDistance = 100f;
public static UIMove Instacne => _instacne;
private UIMove() {
}
//移动
public void Move(RectTransform rt, MoveDirection direction)
{
Vector3 position = rt.position;
rt.position = direction switch
{
MoveDirection.Left => new Vector3(position.x - MoveDistance, position.y, position.z),
MoveDirection.Right => new Vector3(position.x + MoveDistance, position.y, position.z),
MoveDirection.Up => new Vector3(position.x, position.y + MoveDistance, position.z),
MoveDirection.Down => new Vector3(position.x, position.y - MoveDistance, position.z),
_ => throw new ArgumentOutOfRangeException(nameof(direction)),
};
}
}
命令接口 - 抽象命令
public interface ICommand
{
// 执行
void Execute();
// 撤销
void Undo();
// 命令转换字符串
string ToString();
}
移动命令 - 具体命令
public class MoveCommand : ICommand
{
//保持唯一的一份
private readonly UIMove _receiver;
private readonly RectTransform _transform;
private readonly MoveDirection _direction;
public MoveCommand(MoveDirection direction, RectTransform transform)
{
_direction = direction;
_transform = transform;
_receiver = UIMove.Instacne; //单例实例
}
public void Execute() => _receiver.Move(_transform, _direction);
public void Undo()
{
switch (_direction)
{
case MoveDirection.Left:
_receiver.Move(_transform, MoveDirection.Right);
break;
case MoveDirection.Right:
_receiver.Move(_transform, MoveDirection.Left);
break;
case MoveDirection.Up:
_receiver.Move(_transform, MoveDirection.Down);
break;
case MoveDirection.Down:
_receiver.Move(_transform, MoveDirection.Up);
break;
default:
throw new ArgumentOutOfRangeException(nameof(_direction));
}
}
public override string ToString()
{
return _direction.ToString();
}
}
UI 移动调用 - 调用者
public class UIMoveInvoker
{
private List<ICommand> _commands;
private int _index = -1;
public int Index => _index;
public List<ICommand> CommandList => _commands;
public UIMoveInvoker()
{
_commands = new List<ICommand>();
}
//执行移动命令
public void Move(ICommand command)
{
command.Execute();
//如果命令不是最后一个,那就删除后面所有命令
if (_index < _commands.Count - 1)
{
_commands.RemoveRange(_index + 1, _commands.Count - _index - 1);
}
_commands.Add(command);
_index++;
}
//恢复操作
public void ReDo()
{
if (_index >= _commands.Count - 1) return;
_index++;
_commands[_index].Execute();
}
//撤销操作
public void UnDo()
{
if (_index < 0) return;
_commands[_index].Undo();
_index--;
}
}
客户端(使用 GUI 作为可视化处理)
public class CommandExample : MonoBehaviour
{
[SerializeField] private GUIStyle style;
[SerializeField] private RectTransform rectTransform;
private UIMoveInvoker _invoker;
private void Awake()
{
_invoker = new UIMoveInvoker();
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.W)) _invoker.Move(new MoveCommand(MoveDirection.Up, rectTransform));
else if (Input.GetKeyDown(KeyCode.S)) _invoker.Move(new MoveCommand(MoveDirection.Down, rectTransform));
else if (Input.GetKeyDown(KeyCode.A)) _invoker.Move(new MoveCommand(MoveDirection.Left, rectTransform));
else if (Input.GetKeyDown(KeyCode.D)) _invoker.Move(new MoveCommand(MoveDirection.Right, rectTransform));
else if (Input.GetKeyDown(KeyCode.E)) _invoker.UnDo();
else if (Input.GetKeyDown(KeyCode.R)) _invoker.ReDo();
}
private void OnGUI()
{
var list = _invoker.CommandList;
var index = _invoker.Index;
GUILayout.BeginVertical();
GUILayout.Label((index == -1 ? ">> " : "") + "Start", style);
for (int i = 0; i < list.Count; i++)
{
if (i == index) GUILayout.Label(">> " + list[i].ToString(), style);
else GUILayout.Label(list[i].ToString(), style);
}
GUILayout.EndVertical();
}
}
运行结果
解释
应用场景
- 当系统需要支持命令的撤销和恢复时,可以使用命令模式将命令存储起来。
- 当需要将操作进行参数化时,可以使用命令模式
- 需要将请求者和执行者分离解耦,命令模式可以使调用者不直接交互。
- 当系统需要执行一组操作时,命令模式可以定义宏命令来实现该功能。(可以使用组合模式来完成一个组合命令)
优缺点
优点
- 单一职责,调用者和实现者分离。
- 在添加新命令时,无需修改客户端,满足开闭原则
- 可实现撤销和恢复功能
- 可实现宏命令
缺点
- 产生大量命令类,使系统复杂
与其他模式关系
- 原型模式与命令模式搭配,可以对命令进行保存
- 组合模式与命令模式搭配,可以使用组合命令
- 策略模式和命令模式的不同,两者都是通过参数化对象。策略模式看重的上下文的算法切换,描述的是不同方式执行目的。命令模式则是将操作参数化为命令。通过参数化命令,来延时调用,保存记录,发送命令等。
。。。由于还没学完设计模式,其他模式先不比较,先写到着
边栏推荐
- Smart logistics platform: make overseas warehouses smarter
- 浅谈 Apache Doris FE 处理查询 SQL 源码解析
- The mail server is listed in the blacklist. How to unblock it quickly?
- LeetCode 300. 最长递增子序列 每日一题
- 服务器彻底坏了,无法修复,如何利用备份无损恢复成虚拟机?
- Jenkins发布uniapp开发的H5遇到的问题
- 鲲鹏开发者峰会2022 | 麒麟信安携手鲲鹏共筑计算产业新生态
- LeetCode 1186. Delete once to get the sub array maximum and daily question
- QT 图片背景色像素处理法
- MySQL implements the query of merging two fields into one field
猜你喜欢
Skimage learning (3) -- gamma and log contrast adjustment, histogram equalization, coloring gray images
QT picture background color pixel processing method
Seaborn data visualization
SlashData开发者工具榜首等你而定!!!
DevOps 的运营和商业利益指南
Skimage learning (1)
Biped robot controlled by Arduino
NeRF:DeepFake的最终替代者?
Sator launched Web3 game "satorspace" and launched hoobi
QML beginner
随机推荐
【视频/音频数据处理】上海道宁为您带来Elecard下载、试用、教程
【源码解读】| LiveListenerBus源码解读
LeetCode 312. Poke balloon daily
Sator推出Web3遊戲“Satorspace” ,並上線Huobi
The process of creating custom controls in QT to encapsulating them into toolbars (II): encapsulating custom controls into toolbars
mysql使用笔记一
[Fantan] how to design a test platform?
A tour of grpc:03 - proto serialization / deserialization
Flask build API service SQL configuration file
Pychart ide Download
Master this promotion path and share interview materials
Sator launched Web3 game "satorspace" and launched hoobi
What is cloud computing?
QT picture background color pixel processing method
DevOps 的运营和商业利益指南
Pycharm IDE下载
LeetCode 300. Daily question of the longest increasing subsequence
MRS离线数据分析:通过Flink作业处理OBS数据
【Seaborn】组合图表:PairPlot和JointPlot
Flask搭建api服务-生成API文档