当前位置:网站首页>命令模式 - 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();
}
}
运行结果
解释
应用场景
- 当系统需要支持命令的撤销和恢复时,可以使用命令模式将命令存储起来。
- 当需要将操作进行参数化时,可以使用命令模式
- 需要将请求者和执行者分离解耦,命令模式可以使调用者不直接交互。
- 当系统需要执行一组操作时,命令模式可以定义宏命令来实现该功能。(可以使用组合模式来完成一个组合命令)
优缺点
优点
- 单一职责,调用者和实现者分离。
- 在添加新命令时,无需修改客户端,满足开闭原则
- 可实现撤销和恢复功能
- 可实现宏命令
缺点
- 产生大量命令类,使系统复杂
与其他模式关系
- 原型模式与命令模式搭配,可以对命令进行保存
- 组合模式与命令模式搭配,可以使用组合命令
- 策略模式和命令模式的不同,两者都是通过参数化对象。策略模式看重的上下文的算法切换,描述的是不同方式执行目的。命令模式则是将操作参数化为命令。通过参数化命令,来延时调用,保存记录,发送命令等。
。。。由于还没学完设计模式,其他模式先不比较,先写到着
边栏推荐
- 99% 用户在 Power BI 云端报表常犯错误
- 鲲鹏开发者峰会2022 | 麒麟信安携手鲲鹏共筑计算产业新生态
- Reflections on "product managers must read: five classic innovative thinking models"
- 《产品经理必读:五种经典的创新思维模型》的读后感
- Number of exchanges in the 9th Blue Bridge Cup finals
- LeetCode 213. Home raiding II daily question
- SIGGRAPH 2022最佳技术论文奖重磅出炉!北大陈宝权团队获荣誉提名
- 国内首创!Todesk将RTC技术融入远程桌面,画质更清晰操作更流畅
- LeetCode 1043. Separate the array to get the maximum and daily questions
- QT视频传输
猜你喜欢
Matplotlib绘图界面设置
skimage学习(3)——使灰度滤镜适应 RGB 图像、免疫组化染色分离颜色、过滤区域最大值
麒麟信安加入宁夏商用密码协会
User defined view essential knowledge, Android R & D post must ask 30+ advanced interview questions
Seaborn数据可视化
Seaborn data visualization
测试用例管理工具推荐
Reflections on "product managers must read: five classic innovative thinking models"
让保险更“保险”!麒麟信安一云多芯云桌面中标中国人寿, 助力金融保险信息技术创新发展
专精特新软件开发类企业实力指数发布,麒麟信安荣誉登榜
随机推荐
Sator a lancé le jeu web 3 "satorspace" et a lancé huobi
Skimage learning (3) -- adapt the gray filter to RGB images, separate colors by immunohistochemical staining, and filter the maximum value of the region
DNS series (I): why does the updated DNS record not take effect?
PLC: automatically correct the data set noise, wash the data set | ICLR 2021 spotlight
Read PG in data warehouse in one article_ stat
99% of users often make mistakes in power Bi cloud reports
Sator launched Web3 game "satorspace" and launched hoobi
Lex & yacc of Pisa proxy SQL parsing
MySQL usage notes 1
LeetCode 1031. 两个非重叠子数组的最大和 每日一题
MySQL implements the query of merging two fields into one field
Solidity函数学习
How to implement safety practice in software development stage
如何在软件研发阶段落地安全实践
LeetCode 1774. 最接近目标价格的甜点成本 每日一题
《产品经理必读:五种经典的创新思维模型》的读后感
Blue Bridge Cup final XOR conversion 100 points
Biped robot controlled by Arduino
浅谈 Apache Doris FE 处理查询 SQL 源码解析
LeetCode 213. Home raiding II daily question