命令模式
定义与特点
将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。两者通过命令对象进行沟通,这样方便将命令对象进行存储、传递、调用、增加与管理。
优点:
- 用过引入中间件(抽象接口),降低系统的耦合度;
- 扩展性良好,增加或删除命令非常方便。常用命令模式增加和删除命令不会影响其他类,满足“开闭原则”;
- 可以实现宏命令。命令模式额可以与组合模式结合,将多个命令装配成一个组合命令。
- 方便实现 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();
}
@Override
public void execute() {
//System.out.println("具体命令a");
receiverA.action();
}
}
public class ConcreteCommandeB extends Command{
private ReceiverB receiver;
public ConcreteCommandeB(){
receiver = new ReceiverB();
}
@Override
public 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();
}
}