命令模式
定义与特点
将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。两者通过命令对象进行沟通,这样方便将命令对象进行存储、传递、调用、增加与管理。
优点:
- 用过引入中间件(抽象接口),降低系统的耦合度;
- 扩展性良好,增加或删除命令非常方便。常用命令模式增加和删除命令不会影响其他类,满足“开闭原则”;
- 可以实现宏命令。命令模式额可以与组合模式结合,将多个命令装配成一个组合命令。
- 方便实现 Undo和Redo操作。操作模式可以与备忘录模式结合,实现命令的撤销与恢复。
- 可以在现有命令的基础上,增加额外的功能。比如日志记录,结合装饰者模式会更加灵活。
缺点:
- 会产生大量的具体命令类。因为每一个具体操作都需要设计一个具体命令类,增加了系统的复杂性。
效果是,接收方的执行结果,为了以命令的形式进行架构、解耦请求与实现,引入了额外类型结构(引入请求方与抽象命令接口),增加代码结构理解上的难度。
应用场景
请求调用者需要与请求接收者解耦时,命令模式可以使调用者和接收者不直接交互
- 系统随机请求命令或经常增加和删除命令时,该模式比较方便
- 当系统需要执行一组操作时,该模式可以定义宏命令来实现该功能
- 当系统需要支持命令的撤销(Undo)和恢复(Redo)操作时,可以将命令对象存储起来,采用备忘录模式来实现
代码结构与实现
整个代码就是相当于,具体的业务功能放在了实现者/接收者的特定方法里面(action()),然后使用中间件具体命令类和对应的Receiver给封装起来,交给Invoker方法来实现。使用起来有点和抽象工厂模式有些类似
- 抽象命令类(Command):声明执行命令的接口,拥有执行命令的抽象方法 execute()
- 具体命令类(Concrete Command):具体实现类,拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作;
- 实现者/接收者(Receiver):执行命令功能的相关操作,是具体命令对象业务的真正实现者;
- 调用者/请求者(Invoker):是请求的发送者,它通常拥有很多的命令对象,并通过访问命令对象来执行相关请求,它不会执行访问接收者。
抽象命令接口
public abstract class Command {public abstract void execute();}
实现者/接收者
public class ReceiverA {public void action(){System.out.println("接收者的方法");}}public class ReceiverB {public void action(){System.out.println("接收者的方法B,其实就是具体的功能业务");}}
具体抽象命令类
public class ConcreteCommandeA extends Command{private ReceiverA receiverA;public ConcreteCommandeA(){receiverA = new ReceiverA();}@Overridepublic void execute() {//System.out.println("具体命令a");receiverA.action();}}public class ConcreteCommandeB extends Command{private ReceiverB receiver;public ConcreteCommandeB(){receiver = new ReceiverB();}@Overridepublic void execute() {//System.out.println("具体命令B");receiver.action();}}
调用者/请求者
public class Invoker {private Command command;public Invoker(Command command){this.command =command;}public void setCommand(Command co){this.command =co;}public void call(){System.out.println("调用者执行命令command");command.execute();}}
main
public class CommandMain {public static void main(String[] args) {Command command = new ConcreteCommandeA();Invoker invoker = new Invoker(command);invoker.call();Command commandB = new ConcreteCommandeB();Invoker invokerB = new Invoker(commandB);invokerB.call();}}
调用者/请求者(另外一种写法)
public class Invoker {private Command command;public Invoker(Command command){this.command =command;}public void setCommand(Command co){public class InvokerB {private Command commandA,commandB;public void setA(Command a){this.commandA =a;}public void setB(Command b){this.commandB =b;}public void callA(){commandA.execute();}public void callB(){commandB.execute();}}
main对应得调用方法
public class CommandMainB {public static void main(String[] args) {Command coA =new ConcreteCommandeA();Command coB =new ConcreteCommandeB();InvokerB invokerB = new InvokerB();invokerB.setA(coA);invokerB.setB(coB);invokerB.callA();invokerB.callB();}}
命令模式的扩展(宏命令模式)
将命令模式与组合模式联合使用,这就构成了宏命令模式,也叫组合命令模式。宏命令包含了一组命令,它充当了具体命令与调用者的双重角色,执行它时将递归调用它所包含的所有命令
为了简便,其中的抽象接口,以及实现者和具体的命令类都是用上面的,这里就只写管理者和调用方法(main)
调用者/管理者
命令宏—-命令+组合(树)模式:
充当了调用者和命令者(管理者)。
public class CompositeInvoker {private ArrayList<Command> children = new ArrayList<>();public void add(Command co){children.add(co);}public void remove(Command co){children.remove(co);}public Command getChildren(int i){return children.get(i);}public void excute(){for (Object obj:children) {((Command)obj).execute();}}}
main
public class MacroCommand {public static void main(String[] args) {ConcreteCommandeA cca = new ConcreteCommandeA();ConcreteCommandeB ccb = new ConcreteCommandeB();CompositeInvoker ci = new CompositeInvoker();ci.add(cca);ci.add(ccb);ci.excute();}}
