重学设计模式(三设计模式-命令模式)
Posted 穆瑾轩
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重学设计模式(三设计模式-命令模式)相关的知识,希望对你有一定的参考价值。
1、命令模式
在前面我们学习的设计模式中,一般的调用方式就是,客户端发出请求,服务端立即做出响应。这里的请求者与方法的实现者之间都存在紧密的耦合关系,我们无法控制方法执行的时机与上下文。我们的命令模式就是用来将请求或简单的操作转换为对象的行为的。
1.1、什么是命令模式
-
定义
命令模式是一种行为设计模式,它将请求转换为包含有关请求信息的独立对象,将请求和与执行请求的职责分离,方便对请求进行储存、传递、调用的管理,使其可以对请求进行排队、存储请求历史记录或撤销请求等操作。
命令模式可以存储请求对象信息,这些对象可以作为方法参数传递、延迟或排队去执行,所以也可以定位到之前的操作。举个例子:
去餐馆吃饭,顾客找服务员点菜,每一个顾客的点菜都是一个请求,服务员将点菜信息传递给厨师,服务员并不关心菜如何做、谁来做,当顾客一多,就会出现排队的现象,这时候服务员(顾客点菜)和厨师(做菜)各司其职,井井有条才能控制整体的效率。
命令模式的结构:
1)接收者(Receiver)角色:包含一些业务逻辑,是具体命令对象业务的真正实现者;
2)抽象命令类(Command)角色:命令接口通常只声明一个执行命令的方法;
3)具体命令类(Concrete Command)角色:实现各种请求,它拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作;
4)请求者/调用者(Invoker)角色:请求的发送者,通过命令对象来执行请求,包含一些命令对象的引用的信息。它不需要知道接受者是谁,因此只与抽象命令类之间存在关联;
5)客户类(Client)角色:在客户类需要创建调用者对象、具体命令类对象,在创建具体命令对象是指定对应的接收者,发送者和接受者额之间没有直接的关系,都是通过命令对象间接调用的。
命令模式的意图在于:将一个请求封装为一个对象,将请求和与执行请求的职责分离,方便对请求进行储存、传递、调用的管理。
1.2、命令模式的优缺点
-
优点
1)符合单一职责原则,将请求与执行请求的职责分离;
2)可以掌握操作的控制权,实现操作的延迟、撤销等功能;
3)符合开闭原则,可以在不破坏现有代码的情况下引入新的命令;
4)可以实现宏命令,将一组简单的命令组合成一个复杂的命令。
-
缺点
发送者和接收者之间引入了一个全新的层,因此代码可能会变得更加复杂。
1.3、创建方式
我们就以餐馆点菜为例。
1)接收者
//接收者,真正的命令执行者
public class CookReceiver
void actionCooking()
System.out.println("已烹饪完成");
2)抽象命令类、具体命令类
//抽象命令类
public interface HotelCommand
abstract void order(); //点菜
//具体命令类:宫保鸡丁
class ConcreteChicken implements HotelCommand
private CookReceiver receiver; //命令的真正执行者
public ConcreteChicken()
receiver = new CookReceiver();
@Override
public void order()
System.out.println("宫保鸡丁");
System.out.println("加辣");
receiver.actionCooking();
//具体命令类:蛋炒饭
class ConcreteRiceWithEgg implements HotelCommand
private CookReceiver receiver; //命令的真正执行者
public ConcreteRiceWithEgg()
this.receiver = new CookReceiver();
@Override
public void order()
System.out.println("蛋炒饭");
receiver.actionCooking();
3)调用者
//真正的调用者,服务员,也就是接收客户信息并把信息传递给接受者厨师的人
public class WaiterInvoker
private HotelCommand commond;
private List<HotelCommand> commondList;
public WaiterInvoker(HotelCommand commond) //单个单个点
this.commond = commond;
public WaiterInvoker(List<HotelCommand> commondList) //多个一起点
this.commondList = commondList;
public void callCooking()
commond.order();
public void callCookingList()
if(commondList==null)return;
for (HotelCommand hc : commondList)
hc.order();
4)客户类
public class Client
public static void main(String[] args)
//命令
HotelCommand hc = new ConcreteChicken();
//我们发现使用:hc.order()或者new CookReceiver()也能达到相同的效果
//而我们使用命令模式,对单个的请求,与直接调用的区别似乎不大
//但是目的确实不一样的,命令模式加了个中间层,有WaiterInvoker去传递命令
WaiterInvoker wi = new WaiterInvoker(hc);
wi.callCooking();
System.out.println("------------------");
//当请求较多的时候,其实就比较明显了,有个排队处理的效果
HotelCommand hc1 = new ConcreteRiceWithEgg();
List<HotelCommand> all = new ArrayList<HotelCommand>();
all.add(hc);
all.add(hc1);
WaiterInvoker wi1 = new WaiterInvoker(all);
wi1.callCookingList();
此时的UML关系图:
1.4、总结及建议
使用命令模式,可以将任何操作转换为对象。这种转换使得我们可以推迟操作的执行、对其进行排队、存储命令的历史记录、将命令发送到远程服务等。
应用场景:
1)当你想要将操作参数化对象时,可以使用命令模式将特定的方法调用变成一个独立的对象;
2)当你想要实现可逆操作时,可以使用命令模式。比如:数据库的事务机制就是命令模式的应用;
3)当系统要执行一组操作时,命令模式可以定义宏命令来实现该功能。
JDK中命令模式的应用:
java.lang.Runnable
javax.swing.Action
以上是关于重学设计模式(三设计模式-命令模式)的主要内容,如果未能解决你的问题,请参考以下文章