设计模式学习笔记(十七)——Command命令模式

设计模式学习笔记(十七)——Command命令模式

Command命令模式介绍:

Command命令模式是一种对象行为型模式,它主要解决的问题是:在软件构建过程中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”的问题。如下图:

 

有时我们必须向某对象提交请求,但并不知道关于被请求的操作或请求的接受者的任何信息,此时无法抵御变化的紧耦合是不合适的。如:需要对行为进行“记录、撤销/重做、事务”等处理。我们所要做的是将依赖关系转化,将紧耦合变为松耦合。则上图的形式转化为如下形式:



       

 

       Command模式通过将请求本身变成一个对象来使行为请求者可向未指定的应用对象提出请求。

       GoF《设计模式》中说道:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

Command命令模式结构:

      


 

 

定义场景:

       现在来看一个场景:对于notepad大家都很熟悉,在我们使用notepad打开一个文档之后,往往做一些操作,如;输入字符(Write)、删除前一个字符(Delete)、撤销刚才的操作(UnDo)。现在我们就用Console程序模拟这个过程。

代码实现与结构分析:

       在实现代码前先说明实现Command模式需要烤炉的一些问题:

1、  一个命令对象应达到何种智能程度:命令对象的能力可大可小。这样就出现了两个极端。一是:它仅确定一个接收者和执行该请求的动作;一是:它自己实现所有功能,根本不需要额外的接收者对象。我给他们起了便于我方便记忆的名字,第一种叫OperationCommand,第二种叫ObjectCommand。当然只是为了便于记忆和理解,如有不理解,在代码实现与结构分析最后我会再谈谈我的想法,如有不妥,还请多提意见,一会在下面的代码中会分别对这两种情况进行示范。

2、  支持取消和重做:为了达到这个目的ConcreteCommand类中要存储额外的状态信息。也就是上图中ConcreteCommand的state属性。

3、  避免取消操作中过程中的错误积累:由于命令重复的执行、取消执行和重执行的过程可能会积累错误,以致一个应用的状态最终偏离初始值。这就有必要在Command中存入更多的信息以保证这些对象可被精确的复原。

下面来看看代码上的实现:首先,我先作一个OperationCommand的例子,先做一个请求的接收者Document(也就是结构图中的Receiver)

class Document

    {

        public string strContent;

 

        public Document()

        {

            strContent = "";

        }

}

 

在这个程序中我们还要定义一个抽象类Command,对于OperationCommand类型来说,它仅确定一个接收者和执行该请求的动作。所以,在抽象类Command中,只声明一个Excute的方法。这个方法在其子类中进行实现。(当然这个Command还可以定义成接口)

abstract class Command

    {

        public Command()

        { }

        public abstract void Excute();

}

 

接下来,就要实现各种操作(结构图中的ConcreteCommand),代码如下

//写操作

class WriteCommand :Command

    {

        Document doc;

        ArrayList ObjectState;

        public WriteCommand(Document doc,ArrayList state)

        {

            this.doc = doc;

            ObjectState = state;

        }

 

        public override void Excute()

        {

            doc.strContent += Console.ReadLine();

            ObjectState.Add(doc.strContent);

        }

    }

   

    //删除操作

    class DeleteCommand : Command

    {

        Document doc;

        ArrayList ObjectState;

        public DeleteCommand(Document doc,ArrayList state)

        {

            this.doc = doc;

            ObjectState = state;

        }

 

        public override void Excute()

        {

            doc.strContent = doc.strContent.Substring(0, doc.strContent.Length - 1);

            ObjectState.Add(doc.strContent);

        }

    }

 

    //撤销操作

    class UnDoCommand : Command

    {

        Document doc;

        ArrayList ObjectState;

        public UnDoCommand(Document doc,ArrayList state)

        {

            this.doc = doc;

            ObjectState = state;

        }

 

        public override void Excute()

        {

            doc.strContent = (string)ObjectState[ObjectState.Count - 2];

            ObjectState.Add(doc.strContent);

        }

}

 

实现了各种操作后,编写一个客户代码进行测试

class Program

    {

        static void Main(string[] args)

        {

            Document doc = new Document();

            Console.WriteLine("Please Input next operation:");

            string strOperation =Console.ReadLine();

            Command com = null;

            ArrayList ObjectState =new ArrayList();//Record state

            while (strOperation !="Exit")

            {

                switch (strOperation.ToLower())

                {

                    case "write":

                        com = newWriteCommand(doc, ObjectState);

                        com.Excute();

                        Console.WriteLine("Write Operation:" + doc.strContent);

                        break;

                    case "del":

                        com = newDeleteCommand(doc, ObjectState);

                        com.Excute();

                        Console.WriteLine("Delete Operation:" + doc.strContent);

                        break;

                    case "undo":

                        com = newUnDoCommand(doc, ObjectState);

                        com.Excute();

                        Console.WriteLine("UnDo Operation:" + doc.strContent);

                        break;

                    default:

                        Console.WriteLine("Wrong Operation:");

                        break;

                }

                Console.WriteLine("Please Input next operation:");

                strOperation = Console.ReadLine();

            }

        }

}

 

测试结果:

Please Input next operation:

write

k

Write Operation:k

Please Input next operation:

write

i

Write Operation:ki

Please Input next operation:

write

d

Write Operation:kid

Please Input next operation:

write

d

Write Operation:kidd

Please Input next operation:

del

Delete Operation:kid

Please Input next operation:

undo

UnDo Operation:kidd

Please Input next operation:

 

下面再来实现以下ObjectCommand的例子,首先还是编写一个已存在的请求接收者Document(结构图中的Receiver)

class Document

    {

        public string strContent;

 

        public Document()

        {

            strContent = "";

        }

}

 

接下来实现抽象类Command(也可以使用接口),对于ObjectCommand类型来说,它自己实现所有功能,根本不需要额外的接收者对象,所以在Command中声明了所有的操作

abstract class Command

    {

        public Command()

        {  }

 

        public abstract void Write();

        public abstract void Delete();

        public abstract void UnDo();

}

 

有了Command,就可以实现具体的操作类型DocumentCommand(结构图中的ConcreteCommand)

class DocumentCommand :Command

    {

        private Document doc;

        private ArrayList ObjectState = new ArrayList();//Record State

        public DocumentCommand(Document doc)

        {

            this.doc = doc;

        }

 

        public override void Write()

        {

            Console.WriteLine("Please input an character:");

            string strRead = Console.ReadLine();

            doc.strContent += strRead;

            ObjectState.Add(doc.strContent);

        }

 

        public override void Delete()

        {

            doc.strContent = doc.strContent.Substring(0, doc.strContent.Length - 1);

            ObjectState.Add(doc.strContent);           

        }

 

        public override void UnDo()

        {

            doc.strContent = (string)ObjectState[ObjectState.Count - 2];

            ObjectState.Add(doc.strContent);

        }

}  

 

接下来就用一个客户端代码作一下测试

class Program

    {

        static void Main(string[] args)

        {

            Document doc = new Document();

            DocumentCommand com =new DocumentCommand(doc);

            Console.WriteLine("Please Input next operation:");

            string strOperation =Console.ReadLine();

            while (strOperation !="Exit")

            {

                switch (strOperation.ToLower())

                {

                    case "write":

                        com.Write();

                        Console.WriteLine("Write Operation:" + doc.strContent);

                        break;

                    case "del":

                        com.Delete();

                        Console.WriteLine("Delete Operation:" + doc.strContent);

                        break;

                    case "undo":

                        com.UnDo();

                        Console.WriteLine("UnDo Operation:" + doc.strContent);

                        break;

                    default:

                        Console.WriteLine("Wrong Operation:");

                        break;

                }

                Console.WriteLine("Please Input next operation:");

                strOperation = Console.ReadLine();

            }

        }

    }

 

测试结果如下:

Please Input next operation:

write

Please input an character:

k

Write Operation:k

Please Input next operation:

write

Please input an character:

i

Write Operation:ki

Please Input next operation:

write

Please input an character:

d

Write Operation:kid

Please Input next operation:

write

Please input an character:

d

Write Operation:kidd

Please Input next operation:

del

Delete Operation:kid

Please Input next operation:

undo

UnDo Operation:kidd

Please Input next operation:

 

这两个程序中需要有几点说明:

1、              对于OperationCommand,我的理解是它所实现的Command只是某一个操作对于某一个接收者,所以我给它取名为OperationCommand。对于ObjectCommand,是实现这样一种对象,它实现了请求接收者的所有操作,所以取名为ObjectCommand

2、              在代码实例中,我对状态的保存处理相对简单,但这是因为利用了String对象的特点,当String对象被修改时,系统会重新分配一块内存。不修改原内存上的内容。如果是要保存其他的引用类型应当注意使用深拷贝,否则,所保存的状态对象都指向一个内存地址,随着状态的改变,保存不了原有的状态。

3、              在对象状态的保存上,我们可以使用Prototype模式。

Command模式的几个要点:

1、  Command模式的根本目的在于将“行为请求者”与“行为实现者”解耦,在面向对象语言中,常见的实现手段是“将行为抽象为对象”。

2、  实现Command接口的具体命令对象ConcreteCommand 有时候根据需要可能会保存一些额外的状态信息。

3、  通过使用Composite模式,可以将多个“命名”封装为一个“复合命令”MacroCommand。

4、  Command模式与C#中的Delegate有些类似。但两者定义行为接口的规范有所区别:Command以面向对象中的“接口-实现”类定义行为接口规范,更严格,更符合抽象原则:Delegate以函数签名来定义行为接口规范,更灵活,但抽象能力比较弱

http://www.cnblogs.com/kid-li/category/44668.html

转载于:https://www.cnblogs.com/xiayong123/p/3716998.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/294721.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MAUI中Maui.Graphics.Controls绘制控件

简介Microsoft.Maui.Graphics是一个完全采用C#的iOS,Android,Windows,macOS,Tizen和Linux的跨平台图形库。对于MAUI项目当中绘制的方案是使用不同平台的控件来而非自绘。当然MAUI当中也使用了Microsoft.Maui.Graphics,MAUI Previe…

BGP聚合as-set advertise-map

advertise-map xxx 用来挂汇总路由的,当route-map xxx 中的路由存在时,才会出现汇总路由。否则没有汇总路由只继承advertise-map xxx 中路由的属性当汇总路由携带了多个明细属性,可用advertise-map xxx 来移除某个明细路由的路由属性实验拓扑…

Android之如何解决popupWindow(pw.setFocusable(true))按返回键和menu键退出

先爆照: 问题: 使用过popupWindow的时候,我们为了让其它地方不可点击,我们一般会pw.setFocusable(true),但是当我们这样设置之后,问题出现了,按返回键或者menu菜单键没有反应,这是原因呢? PopupWindow 跟我们的 Activity 不一样,因为我们在构造 PW 的时候往往不是继…

上班骚扰男同事被抓到......

1 不同年代的辞职理由(素材来源网络,侵删)▼2 月壤不能种菜太让人失望了▼3 原来,我也努力过▼4 忘了上班还有监控(作者来源最右,ID:8943090 )▼5 这是台风被黑的最惨的一次&…

mysql8 修改权限_MySQL8修改重置root密码,远程连接权限设置

MySQL8 修改重置root密码这里要单独强调是MySQL8,因为在MySQL 8.04前,执行:SET PASSWORDPASSWORD([新密码]);可行,但是MySQL8.0.4开始,这样默认是不行的。因为之前,MySQL的密码认证插件是“mysql_native_pa…

.NET 6新特性试用 | DateOnly和TimeOnly类型

前言在.NET 6之前,没有方法来直接表示没有时间的日期(比如生日)或者没有日期的一天中的时间(比如闹钟)。虽然我们可以使用DateTime类和TimeSpan类来代替,但是实际使用中会存在一些问题:var date…

用wordpress制作网站的总结

在没有自己的网站的时候很像拥有一个属于自己的网站,可以说是自己的一个愿望吧。但是当我真正的运行起来了之后觉得没有多么的兴奋,自己也折腾了几天wordpress,从买域名空间,到安装WP,遇到了一些问题,自己到处搜索答案…

解析super-smack的smack文件

Super-smack是一款强大的数据库压测工具,现在支持mysql和PostgreSQL两种数据库,你可以通过简单的配置文件(.smack)来生成一系列测试环境:测试数据,测试表;在测试的过程中,你可以控制客户端的并发数量以及执…

JSP是不是Java发展史上的一大败笔?

JSP一个年代传奇人物,它的诞生成果了网络的三国鼎立的局势,可是,几年的结构的风烟席卷,让JSP逐渐淡出这个前史舞台,有人不由宣布这样的感叹,JSP是不是Java开展史上的一大败笔呢? 查询样本 让咱们…

Android之使用PopupWindow使用和总结

不废话,先爆照 说明: 那个灰色背景是不能滑动里ListView里面的内容的 第一步:我们需要背景view 下面是我的background.xml文件 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/t…

Cell发文!施一公科研团队取得重大突破

全世界只有3.14 % 的人关注了爆炸吧知识本文来源&#xff1a;科学网&#xff08;有删减&#xff09;北京时间2020年12月29日凌晨0时&#xff0c;《细胞》&#xff08;Cell&#xff09;发表中科院院士、西湖大学校长施一公课题组的一项新研究。研究首次报道了γ-分泌酶&#xff…

MAUI 跨平台播客应用程序(Conf 2021)

介绍在.NET Conf 2021大会上&#xff0c;微软展示了基于.NET6 跨平台应用程序, 具有ASP.NET Core、Blazor、.NET MAUI、微服务等功能。浏览由 ASP.NET Core 和 Blazor 提供支持的 .NET Podcasts 应用的实时运行版本&#xff1a;https://dotnetpodcasts.azurewebsites.net/项目体…

mysql enum_MySQL数据库中关于ENUM类型的详细解释

MySQL数据库中&#xff0c;因为工作的需求&#xff0c;我们可能会用到ENUM类型&#xff0c;但是由于此类型不是很常用&#xff0c;我们可能对其也不是很了解。没关系&#xff0c;本文我们就对ENUM类型做一些详细的解释&#xff0c;希望能够对您有所帮助。ENUM类型是一个字符串对…

Linux系统新手学习的11点建议

随着Linux应用的扩展许多朋友开始接触Linux&#xff0c;根据学习Windwos的经验往往有一些茫然的感觉&#xff1a;不知从何处开始学起。这里介绍学习Linux的一些建议。 一、从基础开始&#xff1a;常常有些朋友在Linux论坛问一些问题&#xff0c;不过&#xff0c;其中大多数的问…

Android之如何实现通讯录的搜索并且让匹配到的数据变颜色

不废话,先爆照 第一步:实现搜索 已经实现了通讯录功能,但是需要搜索,可以支持中文名字搜索,写入电话号码搜索,还有名字拼音,以及名字第一个字的首字母来搜索,这里介绍名字搜索,然后数据是我们公司TCL(020)所有员工的信息,目前还没有写到后…

复习一下日志等级类型

linux操作系统的日志有多种信息等级类型&#xff0c;今天好好复习一下&#xff1a; 1、info&#xff1a;信息说明&#xff1b; 2、notice&#xff1a;较info更需注意的信息&#xff1b; 3、warning&#xff08;warn&#xff09;&#xff1a;和现实生活中的warning不同&#xff…

mysql映射超_Hibernate的映射类型 hibernate mysql映射类型

(转)http://blog.csdn.net/zxy_snow/article/details/7214222Hibernate的映射类型 hibernate mysql映射类型1、Hibernate的映射类型 hibernate mysql映射类型Hibernate 映射类型Java 类型标准 SQL 类型大小和取值范围integer 或者 intint 或者 java.lang.IntegerINTEGER4 字节l…

dotnet 将自动代码格式化机器人带入团队 GitLab 平台

给团队带入一个 代码格式化机器人 能提升团队的幸福度&#xff0c;让团队的成员安心写代码&#xff0c;不用关注代码格式化问题&#xff0c;将格式代码这个粗活交给机器人去做。同时也能减少在代码审查里撕格式化问题的时间&#xff0c;让更多的时间投入到更有价值的工作上本文…

Notion,我来,语雀,有道等几个云笔记

最近打算放弃wolai产品的使用&#xff0c;所以有必要总结一下这些年用过的那些笔记。从最早开始用Evernote&#xff0c;然后麦库&#xff0c;为知&#xff0c;然后有道&#xff0c;onenote&#xff0c;一直到Notion&#xff0c;我来&#xff0c;语雀等等&#xff0c;都有各自的…

玩转Javascript 给JS写测试

给js写测试已经不是什么稀奇的事情了&#xff0c;最近项目里用了jasmine和JsTestDriver两种js测试框架。JsTestDriver易于与持续构建系统相集成并能够在多个浏览器上运行测试轻松实现TDD风格的开发。当在项目中配置好JsTestDriver以后&#xff0c;如同junit测试java文件一般&am…