设计模式——命令模式

更多内容,前往 IT-BLOG

软件开发中,通常会存在 “方法的请求者” 与 “方法的实现者” 之间存在紧密的耦合关系。这不利于软件功能的扩展与维护。特别是针对行为进行(撤销、重做、记录)一系列操作时很不方便,因此 “如何将方法的请求者与方法的实现者解耦”,是命令模式的主要任务和功能。在现实生活中,这样的例子也很多,例如,电视机遥控器(命令发送者)通过按钮(具体命令)来遥控电视机(命令接收者)

一、命令模式的基本介绍


1)、命令模式(Command Pattern):是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传递给对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
2)、命令模式使得请求发送者与请求接受者消除彼此之间的耦合,让对象之间的调用关系更加灵活,实现解耦。
3)、在命令模式中,会将一个请求封装为一个对象,以便使用不同的参数(执行者)来表示不同的请求。同时命令模式也支持撤销的操作。
4)、增加或删除命令非常方便。采用命令模式增加和删除命令不会影响其他类,它满足 “开闭原则” ,即扩展灵活。
5)、可以实现宏命令。命令模式可以与组合模式结合,将多个命令装配成一个组合命令,即宏命令。
6)、方便实现 Undo 和 Redo 操作(适合命令模式)。命令模式可以与后面介绍的备忘录模式结合,实现命令的撤销与恢复。
7)、其缺点是:可能产生大量具体命令类。因为对每一个具体操作都需要设计一个具体命令类,这将增加系统的复杂性。

二、命令模式结构类图


 命令模式包含以下主要角色
【1】、接口命令(Command)角色:声明执行命令的接口,拥有执行命令的抽象方法。
【2】、具体命令(Concrete Command)角色:是抽象命令类的具体实现类,它拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作。
【3】、接收者(Receiver)角色:执行命令功能的相关操作,是具体命令对象业务的真正实现者。
【4】、调用者(Invoker)角色:是请求的发送者,它通常拥有很多的命令对象,并通过访问命令对象来执行相关请求,不直接访问接收者。

三、命令模式案例分析


我们通过写一个空调遥控器按钮的案例来体会命令模式的特点

【1】接口命令角色:Command,其包含两个主要方法(execute() 与 undo())

1 public interface Command {
2     //命令的执行方法
3     public void execute();
4     //撤销操作
5     public void undo();
6 }

【2】 具体命令实现类:写一个制热的命令类,实现命令接口,并组合接受者角色,调用目标方法。类似的类还有制冷等等。

 1 //制热命令
 2 public class HeadCommand implements Command{
 3     //组合空调具体执行类
 4     private AirCondition airCondition;
 5     //构造器
 6     public HeadCommand(AirCondition airCondition) {
 7         super();
 8         this.airCondition = airCondition;
 9     }
10 
11     @Override
12     public void execute() {
13         //调用空调的制热方法
14         airCondition.Head();
15     }
16 
17     @Override
18     public void undo() {
19         //返回上一次操作
20         airCondition.refrigeration();
21     }
22     
23 }

【3】接收者角色:空调类(AirCondition )

 1 //空调类
 2 public class AirCondition {
 3     //制热
 4     public void Head() {
 5         System.out.println("空调制热.......");
 6     }
 7     //制冷
 8     public void  refrigeration() {
 9         System.out.println("空调开始制冷......");
10     }
11 }

【4】调用者角色:遥控器类 (RemoteController )

 1 //调用者( 遥控器 ),也是命令模式的精华
 2 public class RemoteController {
 3     //添加命令按钮
 4     Command[] commands;
 5     //撤销按钮
 6     Command undo;
 7     //构造器
 8     public RemoteController() {
 9         //初始化按钮
10         commands = new Command[5];
11         for(int i=0;i<5;i++) {
12             commands[i] = new NoCommand();
13         }
14     }
15     
16     //给遥控器添加按钮
17     public void setCommand(int n , Command command) {
18         commands[n]=command;
19     }
20     
21     //调用制热按钮
22     public void headCommonButton(int n) {
23         commands[n].execute();
24     }
25     
26     //撤回
27     public void undoButton() {
28         undo.undo();
29     }
30     
31 }

【5】客户端调用

 1 public class Client {
 2     public static void main(String[] args) {
 3         //创建空调实例
 4         AirCondition airCondition = new AirCondition();
 5         //调用命令类
 6         RemoteController remoteController = new RemoteController(); 
 7         //将命令添加至遥控按钮中
 8         HeadCommand headCommand = new HeadCommand(airCondition);
 9         remoteController.setCommand(0,headCommand);
10         //调用制热功能
11         remoteController.headCommonButton(0);
12     }
13 }

注意命令模式的好处:当增加新产品时,只需要创建新产品类即可。无需修改命令类,符合开闭原则。例如我们增加一个冰箱的制热功能。只需要添加冰箱实体类和制热命令类,同时在客户端将其添加至命令类中即可,无需修改命令类。

 
posted @ 2020-11-19 14:27  Java程序员进阶  阅读(157)  评论(0编辑  收藏  举报