三分钟理解“命令模式”——设计模式轻松掌握

什么是命令模式?

假设现在有一个请求处理类(低层类/第三方类),如果客户端拿到这个类之后直接调用它,那么客户端和这个请求处理类之间的藕合度过高。

这时候我们在客户端的请求发送类和请求处理类之间增加一个Invoker类,再将请求发送类发送的所有请求封装成对象,然后让Invoker类去管理这些请求对象,并决定这些请求是否允许执行、何时执行、按什么顺序执行。

由于在请求发送类和请求处理类之间增加了请求转发者,因此这两个类之间的藕合度就大大降低。

命令模式的类图

1.Invoker类用于管理客户端想要发送的请求Command;

Invoker中有一个List<Command>,用于存放客户端发来的还没有被执行的请求;

客户端通过Invoker类中的add、delete函数,向Invoker发送或删除请求;

客户端通过Invoker类的executeCommand()函数,一次性执行Invoker中尚未被执行的请求。

2.当客户端执行Invoker的executeCommand()函数时,该函数实际调用了当前Command对象肚子中的executeCommand()函数。

Command类中含有请求处理者Receiver的对象,客户端通过Command对象中的setReceiver(Receiver)函数来设置;

当客户端调用Invoker的executeCommand()时,该函数调用了当前Command对象的executeCommand()函数,该函数再调用Command肚子中那个Receiver对象的具体处理函数。

客户端代码:

main(){
	//创建Receiver对象
	Receiver receiver = new Receiver();

	//创建Command对象,并往Command肚子里设置该命令所要执行的处理类的对象
	Command commandA = new ConcreteCommandA();
	commandA.setReceiver(receiver);

	Command commandB = new ConcreteCommandB();
	commandB.setReceiver(receiver);

	//创建Invoker对象,并往它肚子里添加需要处理的命令
	Invoker invoker = new Invoker();
	invoker.add(commandA);
	invoker.add(commandB);

	//执行Invoker肚子里的所有命令
	invoker.executeCommand();
}

命令模式的优点

1.命令模式将请求发送者和请求处理者分离开,从而降低了这两个类之间的藕合;

2.通过在请求发送者和请求处理者之间增加转发类的方式,从而客户端发出的请求可以在被处理之前都存放在Invoker类的容器中,请求在被执行前就有了一个缓冲,能起到以下作用:

a)Invoker能够对客户端发出的请求进行排序;

b)Invoker能够决定是否需要驳回请求;

c)客户端可以在请求被执行前选择撤销某个请求;

d)在需要的情况下,客户端的请求可以被记录成日志;

3.增加新的命令时只需增加新的命令子类即可。

是否需要在程序设计的时候去猜测未来可能发生的事情?

不需要!敏捷开发原则告诉我们:不要为代码添加基于猜测的功能!

如果不清楚一个系统是否需要命令模式,就不要着急着去实现它;在需要的时候通过重构代码实现这个模式。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java编程技术

高并发编程必备基础(上)

借用Java并发编程实践中的话"编写正确的程序并不容易,而编写正常的并发程序就更难了",相比于顺序执行的情况,多线程的线程安全问题是微妙而且出乎意料的,因为在没...

992
来自专栏Play & Scala 技术分享

Play Scala 2.5.x - Play with MongoDB 开发指南

3305
来自专栏Android-JessYan

你不知道的Retrofit缓存库RxCache前言简介使用详解总结

1712
来自专栏北京马哥教育

经典!Python运维中常用的几十个Python运维脚本

本文由马哥教育Python自动化实战班4期学员推荐,转载自互联网,作者为mark,内容略经小编改编和加工,观点跟作者无关,最后感谢作者的辛苦贡献与付出。 fil...

6934
来自专栏Android 开发学习

Android内存泄漏分析总结

1764
来自专栏coder修行路

爬虫性能相关

这里我们通过请求网页例子来一步步理解爬虫性能 当我们有一个列表存放了一些url需要我们获取相关数据,我们首先想到的是循环 简单的循环串行 这一种方法相对来说是最...

2047
来自专栏大内老A

Self Host模式下的ASP. NET Web API是如何进行请求的监听与处理的?

构成ASP.NET Web API核心框架的消息处理管道既不关心请求消息来源于何处,也不需要考虑响应消息归于何方。当我们采用Web Host模式将一个ASP.N...

3035
来自专栏一个会写诗的程序员的博客

《Kotin 极简教程》第9章 轻量级线程:协程(2)《Kotlin极简教程》正式上架:

如果需要依次调用它们, 我们只需要使用正常的顺序调用, 因为协同中的代码 (就像在常规代码中一样) 是默认的顺序执行。下面的示例通过测量执行两个挂起函数所需的总...

1172
来自专栏刘望舒

Android深入理解JNI(一)JNI原理与静态、动态注册

前言 JNI不仅仅在NDK开发中应用,它更是Android系统中Java与Native交互的桥梁,不理解JNI的话,你就只能停留在Java Framework层...

3417
来自专栏恰同学骚年

.NET基础拾遗(5)多线程开发基础

  下面的一些基本概念可能和.NET的联系并不大,但对于掌握.NET中的多线程开发来说却十分重要。我们在开始尝试多线程开发前,应该对这些基础知识有所掌握,并且能...

1202

扫码关注云+社区