LieBrother原文:
行为型模式:命令模式
十一大行为型模式之三:命令模式。
简介姓名 :命令模式
英文名 :Command Pattern
价值观 :军令如山
个人介绍 :
Encapsulate a request as an object,thereby letting you parameterize clients with different requests,queue or log requests,and support undoable operations.
将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。
(来自《设计模式之禅》)
作为一个程序猿,我们每天都在经历着命令模式,技术经理把需求任务分配给工程师开发,有时因为第三方或者其他不可抗拒的因素导致需求停止开发。这种工作模式就是命令模式。好了,开始故事了。小明在 XX 科技公司做一个安静的程序猿,有一天技术经理给他分配了一个任务:新增黑名单,也就是在他们系统的某个模块里面可以手工对电话打黑名单标签的功能。小明接到任务后就立马开发,在开发了 2 天之后,因为战略原因,技术经理大明暂停了这个开发任务,接下来我们通过非命令模式和命令模式 2 种代码实现来体现这个过程。在这个场景中,为了简单,我们假定技术经理大明手下只有小明一个开发人员。
非命令模式非命令模式也就是不使用命令模式的代码实现。代码中,我们出现了 Developer 开发人,开发同学是接受技术经理传达的任务,技术经理让他开发哪个需求就开发哪个需求,如果项目有问题需要中断,也需要技术经理评估后传达给开发同学,所以 Developer 有 2 个方法,分别是 develop() 开发需求和 suspend() 暂停需求。 Requirement 则为需求类,TechnicalManager1 则为技术经理类,他有一个方法 action(),通过这个方法来指定开发同学开发任务或者暂停任务。
public class NoCommandTest { public static void main(String[] args) { Developer xiaoMing = new Developer("小明"); Requirement requirement = new Requirement("新增黑名单"); TechnicalManager1 technicalManager2 = new TechnicalManager1("大明"); technicalManager2.setDeveloper(xiaoMing); technicalManager2.action(requirement, "develop"); System.out.println("开发了 2 天,需求变故,需要暂停。。。"); technicalManager2.action(requirement, "suspend"); } } /** * 开发人员 */ class Developer { private String name; public Developer(String name) { this.name = name; } public void develop(Requirement requirement) { System.out.println(this.name + " 开始开发需求:" + requirement.getName()); } public void suspend(Requirement requirement) { System.out.println(this.name + " 停止开发需求:" + requirement.getName()); } public String getName() { return name; } } /** * 需求 */ class Requirement { private String name; public Requirement(String name) { this.name = name; } public String getName() { return name; } } /** * 技术经理 */ class TechnicalManager1 { private String name; private Developer developer; public TechnicalManager1(String name) { this.name = name; } public void setDeveloper(Developer developer) { this.developer = developer; } public void action(Requirement requirement, String type) { if ("develop".equals(type)) { this.developer.develop(requirement); } else if ("suspend".equals(type)) { this.developer.suspend(requirement); } } } 打印结果: 小明 开始开发需求:新增黑名单 开发了 2 天,需求变故,需要暂停。。。 小明 停止开发需求:新增黑名单通过代码,我们可以发现技术经理和开发同学是强依赖关系。如果技术经理下达了一个任务,要求小明写一下周报,这时候得怎么写?是不是小明需要一个写周报的方法,大明也需要新增一个处理事务类型?有没有更好的方法让技术经理不需要做任何改变?命令模式就来解决这个问题。
命令模式在这个例子中,不管大明叫小明做什么事情,其实都是一样的,就是下达任务命令,让小明去执行命令。我们可以利用命令模式把下达任务这个抽象起来,当做父类,下达开发命令、下达暂停命令、下达写周报等等都是不同的子命令。代码如下。
public class CommandTest { public static void main(String[] args) { Developer xiaoMing = new Developer("小明"); Command developCommand = new DevelopCommand(xiaoMing); Command suspendCommand = new SuspendCommand(xiaoMing); Requirement requirement = new Requirement("新增黑名单"); TechnicalManager2 technicalManager = new TechnicalManager2("大明"); technicalManager.setCommand(developCommand); technicalManager.action(requirement); System.out.println("开发了 2 天,需求变故,需要暂停。。。"); technicalManager.setCommand(suspendCommand); technicalManager.action(requirement); } } /** * 命令 */ abstract class Command { protected Developer developer; public Command(Developer developer) { this.developer = developer; } public abstract void execute(Requirement requirement); } /** * 开始开发 */ class DevelopCommand extends Command { public DevelopCommand(Developer developer) { super(developer); } @Override public void execute(Requirement requirement) { this.developer.develop(requirement); } } /** * 开发中断 */ class SuspendCommand extends Command { public SuspendCommand(Developer developer) { super(developer); } @Override public void execute(Requirement requirement) { this.developer.suspend(requirement); } } /** * 技术经理 */ class TechnicalManager2 { private String name; private Command command; public TechnicalManager2(String name) { this.name = name; } public void action(Requirement requirement) { this.command.execute(requirement); } public void setCommand(Command command) { this.command = command; } } 打印结果: 小明 开始开发需求:新增黑名单 开发了 2 天,需求变故,需要暂停。。。 小明 停止开发需求:新增黑名单