【Java设计模式】 Java设计模式之(六)命令模式(Command Pattern)
命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
一、命令模式介绍
意图:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。
主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。
何时使用:在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。
如何解决:通过调用者调用接受者执行命令,顺序:调用者→命令→接受者。
关键代码:定义三个角色:1、received 真正的命令执行对象 2、Command 3、invoker 使用命令对象的入口
应用实例:struts 1 中的 action 核心控制器 ActionServlet 只有一个,相当于 Invoker,而模型层的类会随着不同的应用有不同的模型类,相当于具体的 Command。
优点: 1、降低了系统耦合度。 2、新的命令可以很容易添加到系统中去。
缺点:使用命令模式可能会导致某些系统有过多的具体命令类。
使用场景:认为是命令的地方都可以使用命令模式,比如: 1、GUI 中每一个按钮都是一条命令。 2、模拟 CMD。
注意事项:系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作,也可以考虑使用命令模式,见命令模式的扩展。
二、代码实现
所有设计模式的代码实现例子都可在码云上查看哦,感兴趣的可以查看哈,码云地址:https://gitee.com/no8g/java-design-patterns
2.1 通用类图
在这个类图中,我们看到三个角色:
Receiver 角色:这个就是干活的角色,命令传递到这里是应该被执行的,具体到上面我们的例子中就是Group 的三个实现类;
Command 角色:就是命令,需要我执行的所有命令都这里声明;
Invoker 角色:调用者,接收到命令,并执行命令,例子中我这里项目经理就是这个角色;
命令模式比较简单,但是在项目中使用是非常频繁的,封装性非常好,因为它把请求方(Invoker)和执行方(Receiver)分开了,扩展性也有很好的保障。但是,命令模式也是有缺点的,你看 Command 的子类没有,那个如果我要写下去的可不是几个,而是几十个,这个类膨胀的非常多,这个就需要大家在项目中自己考虑使用了。
2.2 代码实现
package com.iot.practice.designpattern.command.commandpattern;/** * <p>CommandClient 此类用于:</p> * <p>@author:hujm</p> * <p>@date:2021年02月19日 15:45</p> * <p>@remark:</p> */public class CommandClient { public static void main(String[] args) { // 定义我们的接头人 Invoker zhangSan = new Invoker(); // 客户要求增加一项需求 System.out.println("\n-------------客户要求增加一项需求-----------------"); // 客户给我们下命令来 Command command = new AddRequirementCommand(); // 接头人接收到命令 zhangSan.setCommand(command); // 接头人执行命令 zhangSan.action(); // 客户要求增加一项需求 System.out.println("\n-------------客户要求删除一个页面-----------------"); // 客户给我们下命令来 Command command1 = new DeletePageCommand(); //接头人接收到命令 zhangSan.setCommand(command1); //接头人执行命令 zhangSan.action(); }}
package com.iot.practice.designpattern.command.commandpattern;import com.iot.practice.designpattern.command.CodeGroup;import com.iot.practice.designpattern.command.PageGroup;import com.iot.practice.designpattern.command.RequirementGroup;/** * <p>Command 此类用于:</p> * <p>@author:hujm</p> * <p>@date:2021年02月19日 15:34</p> * <p>@remark:命令的抽象类,我们把客户发出的命令定义成一个一个的对象</p> */public abstract class Command { /** * 把三个组都定义好,子类可以直接使用 * * 需求组 */ protected RequirementGroup requirementGroup = new RequirementGroup(); /** * 美工组 */ protected PageGroup pageGroup = new PageGroup(); /** * 代码组 */ protected CodeGroup codeGroup = new CodeGroup(); /** * 只要一个方法,你要我做什么事情 */ public abstract void execute();}
package com.iot.practice.designpattern.command.commandpattern;/** * <p>Invoker 此类用于:</p> * <p>@author:hujm</p> * <p>@date:2021年02月19日 15:42</p> * <p>@remark:接头人的职责就是接收命令,并执行</p> */public class Invoker { /** * 什么命令 */ private Command command; /** * 客户发出命令 */ public void setCommand(Command command) { this.command = command; } /** * 执行客户的命令 */ public void action() { this.command.execute(); }}
package com.iot.practice.designpattern.command.commandpattern;/** * <p>AddRequirementCommand 此类用于:</p> * <p>@author:hujm</p> * <p>@date:2021年02月19日 15:38</p> * <p>@remark:增加一项需求</p> */public class AddRequirementCommand extends Command { /** * 执行增加一项需求的命令 */ @Override public void execute() { // 找到需求组 super.requirementGroup.find(); // 增加一份需求 super.requirementGroup.add(); // 给出计划 super.requirementGroup.plan(); }}
package com.iot.practice.designpattern.command.commandpattern;/** * <p>DeleltePageCommand 此类用于:</p> * <p>@author:hujm</p> * <p>@date:2021年02月19日 15:41</p> * <p>@remark:<删除一个页面的命令/p> */public class DeletePageCommand extends Command { /** * 执行删除一个页面的命令 */ @Override public void execute() { // 找到页面组 super.pageGroup.find(); // 删除一个页面 super.pageGroup.delete(); // 给出计划 super.pageGroup.plan(); }}
package com.iot.practice.designpattern.command;/** * <p>Group 此类用于:</p> * <p>@author:hujm</p> * <p>@date:2021年02月19日 15:11</p> * <p>@remark:项目组分成了三个组,每个组还是要接受增删改的命令</p> */public abstract class Group { /** * 甲乙双方分开办公,你要和那个组讨论,你首先要找到这个组 */ public abstract void find(); /** * 被要求增加功能 */ public abstract void add(); /** * 被要求删除功能 */ public abstract void delete(); /** * 被要求修改功能 */ public abstract void change(); /** * 被要求给出所有的变更计划 */ public abstract void plan();}
package com.iot.practice.designpattern.command;/** * <p>RequirementGroup 此类用于:</p> * <p>@author:hujm</p> * <p>@date:2021年02月19日 15:14</p> * <p>@remark:</p> */public class RequirementGroup extends Group { @Override public void find() { System.out.println("找到需求组..."); } @Override public void add() { System.out.println("客户要求增加一项需求..."); } @Override public void delete() { System.out.println("客户要求删除一项需求..."); } @Override public void change() { System.out.println("客户要求修改一项需求..."); } @Override public void plan() { System.out.println("客户要求需求变更计划..."); }}
package com.iot.practice.designpattern.command;/** * <p>PageGroup 此类用于:</p> * <p>@author:hujm</p> * <p>@date:2021年02月19日 15:23</p> * <p>@remark:美工组的职责是设计出一套漂亮、简单、便捷的界面</p> */public class PageGroup extends Group { @Override public void find() { System.out.println("找到美工组..."); } @Override public void add() { System.out.println("客户要求增加一个页面..."); } @Override public void delete() { System.out.println("客户要求删除一个页面..."); } @Override public void change() { System.out.println("客户要求修改一个页面..."); } @Override public void plan() { System.out.println("客户要求页面变更计划..."); }}
package com.iot.practice.designpattern.command;/** * <p>CodeGroup 此类用于:</p> * <p>@author:hujm</p> * <p>@date:2021年02月19日 15:27</p> * <p>@remark:代码组的职责是实现业务逻辑,当然包括数据库设计了</p> */public class CodeGroup extends Group { @Override public void find() { System.out.println("找到代码组..."); } @Override public void add() { System.out.println("客户要求增加一项功能..."); } @Override public void delete() { System.out.println("客户要求删除一项功能..."); } @Override public void change() { System.out.println("客户要求修改一项功能..."); } @Override public void plan() { System.out.println("客户要求代码变更计划..."); }}
完结!