轻松实现记录与撤销——C#中的Command模式
Command模式属于行为模式,作为大名鼎鼎的23个设计模式之一,Command模式理解起来不如工厂模式,单例模式等那么简单直白。究其原因,行为模式着重于使用,如果没有编程实践,确实不如创造模式那么直白。我们先看看UML类图。
估计很多同学看着图就晕了,那么多东西,Command和Concrete Command还好理解,那些Receiver和Invoker又是什么东西呢?
别着急,只要理解了一点,这个模式就很容易理解了,下面划重点,Command模式最主要的特点,是将命令封装成类,在类中保存命令执行的上下文(即该命令执行的参数,执行的对象),以实现命令执行对象和命令发出对象的解耦。
这样一来是不是觉得好理解多了?Command类里面的Receiver,就是命令具体执行的对象。这里的Client可以理解为装配环境,在这里面代码实例化Command。Invoker内部保存命令(可以保存多条命令,实现命令记录查看,撤销等),客户端代码通过Invoker来操作命令。接下来我们看看示例代码。
定义Command接口
首先我们定义一个支持撤销的Command接口。
interface Command
{
void Execute();
void Undo();
}
定义Receiver
接下来我们定义Receiver,也就是命令的执行对象,这里我们定义一个Ball类。
class Ball
{
public int Size { get; set; } = 10;
public string Name { get; set; } = "My First Ball";
public void Inspect()
{
Console.WriteLine("My Name is {0} and size is {1}", Name, Size);
}
}
定义具体命令
这里定义两个命令,一个修改名字,一个修改大小。
class ChangeNameCommand : Command
{
private Ball _Ball;
private string _OldName;
public string NameYouWant { get; set; }
public ChangeNameCommand(Ball ball)
{
_Ball = ball;
}
public void Execute()
{
_OldName = _Ball.Name;
_Ball.Name = NameYouWant;
}
public void Undo()
{
_Ball.Name = _OldName;
}
}
class ChangeSizeCommand : Command
{
//代码大同小异,略
}
定义Invoker
接下来是Invoker,,也就是存储命令,并最终会被用户代码调用的类,这里我们叫它CommandManager。
class CommandManager
{
private Stack<Command> commands = new Stack<Command>();
public void RunCommand(Command command)
{
command.Execute();
commands.Push(command);
}
public void Undo()
{
if (commands.Count > 0)
{
var command = commands.Pop();
command.Undo();
}
}
public void ShowCommands()
{
var temp = commands.Reverse();
foreach(var command in temp)
{
//display command
}
}
}
使用命令
现在我们看看客户端代码是怎么使用他们的,定义Ball,定义命令,通过CommandManager去调用,这样可以方便查看命令记录,撤销命令,等。
static void Main(string[] args)
{
Ball ball = new Ball();
ball.Inspect();
ChangeNameCommand changeName = new ChangeNameCommand(ball) { NameYouWant = "Changed" };
ChangeSizeCommand changeSize = new ChangeSizeCommand(ball) { SizeYouWant = 20 };
CommandManager manager = new CommandManager();
manager.RunCommand(changeName);
manager.RunCommand(changeSize);
ball.Inspect();
manager.ShowCommands();
manager.Undo();
ball.Inspect();
manager.Undo();
ball.Inspect();
}
就酱,我们已经实现了命令模式,并且还支持命令的记录与撤销,希望能对大家有点帮助。
轻松实现记录与撤销——C#中的Command模式的更多相关文章
- (转)轻松学,Java 中的代理模式及动态代理
背景:讲到反射机制,肯定会想到动态代理. 轻松学,Java 中的代理模式及动态代理 代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强.值得注意的是,代理类和被代理类应该 ...
- oracle数据库学习记录(持续更新中...)
--------------------------------------------day1------------------------------------------------- 1. ...
- 记录自己在 cmd 中执行 jar 文件遇到的一些错误
记录自己在 cmd 中执行 jar 文件遇到的一些错误 场景: 请求接口,解析接口返回的 JSON 字符串并插入到我们的数据库里面. 情况: 项目在 eclipse 中正常运行,打成 jar 包后在 ...
- 【我的Android进阶之旅】Android Studio如何轻松整理字符串到string.xml中
使用Android Studio一段时间了,还有很多小技巧没有掌握.比如:平常将字符串整理到string.xml中,都是手动的去复制字符串到string.xml中,然后再回来修改引用该字符串的代码,这 ...
- Tomcat在windows服务器下,将tomcat控制台日志记录到日志文件中
Tomcat在windows服务器下,将tomcat控制台日志记录到日志文件中 在Linux系统中,Tomcat 启动后默认将很多信息都写入到 catalina.out 文件中,我们可以通过tail ...
- 【js 正则表达式】记录所有在js中使用正则表达式的情况
说实话,对正则表达式有些许的畏惧感,之前的每次只要碰到需要正则表达式去匹配的情况,都会刻意的躲过或者直接从度娘处获取. 此时此刻,感觉到了某一个特定的点去触及她.但笔者对于正则表达式使用上的理解是这样 ...
- 零元学Expression Blend 4 - Chapter 41 Flash做的到的Blend也可以!轻松制作拥有动画的MenuBar!(中)
原文:零元学Expression Blend 4 - Chapter 41 Flash做的到的Blend也可以!轻松制作拥有动画的MenuBar!(中) 我们接着进行动画MenuBar的制作 接续着上 ...
- 制作类似ThinkPHP框架中的PATHINFO模式功能
一.PATHINFO功能简述 搞PHP的都知道ThinkPHP是一个免费开源的轻量级PHP框架,虽说轻量但它的功能却很强大.这也是我接触学习的第一个框架.TP框架中的URL默认模式即是PathInfo ...
- 如何设置Win7系统中的上帝模式GodMode(转载)
如何设置Win7系统中的上帝模式GodMode(转载) NT6系统中隐藏了一个秘密的“GodMode”,字面上译为“上帝模式”.God Mode其实就是一个简单的文件夹窗口,但包含了几乎所有系统的设置 ...
随机推荐
- Java笔记(day23-day26)
IO流1,复制一个文本文件. 1,明确体系: 源:InputStream ,Reader 目的:OutputStream ,Writer 2,明确数据: ...
- Java——一文读懂Spring MVC执行流程
说到Spring MVC执行流程,网上有很多这方面的文章介绍,但是都不太详细,作为一个初学者去读会有许多不理解的地方,今天这篇文章记录一下我学习Spring MVC的心得体会 话不多说,先上图: Sp ...
- EOS基础全家桶(十)交易Action操作
简介 区块链上的所有操作都是通过交易(Transaction)上链的,无论你是转账交易还是发起的智能合约的调用,而EOS和传统区块链不同的是EOS在一个交易里可以发起多个行为(Action),这使得E ...
- HDU1300Pearls
传送门 描述: 有几种不同的珍珠.每种珍珠都有它的单价.当然质量高的珍珠价格一定也是高的. 为了避免买家只买1个珍珠.就要求不论是买了多少个珍珠都是需要在购买数量上加10.之后乘上单价. 例如:买5个 ...
- spring对websocket的集成和使用
WebSocket是HTML5提出的一个用于通信的协议规范,该协议通过一个握手机制,在客户端和服务端之间建立一个类似于TCP的连接,从而方便客户端和服务端之间的通信. WebSocket协议本质上是一 ...
- VM虚拟机手动配置IP地址
1.查看虚拟机的网关 编辑-->虚拟网络编辑器 VMnet8 NAT模式-->NAT设置-->网关IP 2.设置IP地址 系统-->首选项-->网络连接 system e ...
- mysql中的读锁和写锁
当mysql为一个表开启读锁的时候,其他进程包括进程本身没有权利去修改这张表的内容,也没有权利更新,但是可以读取表里面的内容 如下例子 给表上读锁 接着更新一下,显示被锁了 释放锁并插入数据 写锁 查 ...
- GitHub 热点速览 Vol.19:如何叩响大厂的门?
作者:HelloGitHub-小鱼干 摘要:进大厂,无疑是升职加薪走上人生巅峰的一个敲门砖,那,如何拿到这个敲门砖呢?前辈的经验之谈,无疑会给我们进大厂带来许多的经验参考,本周的#大厂面试经验之谈#主 ...
- FOC: Park变换电角度误差带来的影响
关于坐标变换已经在这篇博客中提到<FOC中的Clarke变换和Park变换详解>,在FOC算法的实际调试过程中会遇到很多与理论有所偏差的问题,往往这些情况下,需要对理论有较深刻的理解,才能 ...
- ubuntu文件系统修改( for arm)
系统:ubuntu14.04 镜像:ubuntu-rootfs.img for aarch64 创建一个文件夹 ubuntu-mount mkdir ubuntu-mount 将ubuntu-root ...