你需要了解的行为型设计模式之命令模式

行为型设计模式之命令模式

解释

命令模式顾名思义就是

对命令进行封装,将一个个命令抽出来变成对象,使调用命令者实现命令者之间达到松耦合

意义

  1. 解耦
  2. 易扩展
  3. 组合命令
  4. 命令的记录

举例

不使用命令模式

例子解决一切,我们来说一个通过遥控器控制电视机的案例

角色

Invoker 调用者(遥控器)

Receiver 实现者(电视)

Client 来实现效果的类(我们)

Achievable 功能接口(开电源,换台,关电源)

代码

Achievable

public interface Achievable {

    void open();

    void close();

    void next(int channel);
}

Receiver

public class Receiver implements Achievable {

    @Override
    public void open() {
        System.out.println("开机");
    }

    @Override
    public void close() {
        System.out.println("关机");
    }

    @Override
    public void next(int channel) {
        System.out.println("换台" + channel);
    }
}

Invoker

public class Invoker implements Achievable{

    private Receiver receiver;

    public void setReceiver(Receiver receiver) {
        this.receiver = receiver;
    }

    @Override
    public void open() {
        receiver.open();
    }

    @Override
    public void close() {
        receiver.close();
    }

    @Override
    public void next(int channel) {
        receiver.next(channel);
    }
}

操控

public class Client {

    public static void main(String[] args) {

        Invoker invoker = new Invoker();
        invoker.setReceiver(new Receiver());
        invoker.open();
        invoker.next(1);
        invoker.close();

    }
}

结果

开机
换台1
关机
意外发现

本来没打算使用设计模式,定睛一看,这就是个代理模式。。先不管代理模式,有人说,遥控器多此一举,直接

public class Client {

    public static void main(String[] args) {
        
        Receiver receiver=new Receiver();
        receiver.open();
        receiver.next(1);
        receiver.close();

    }
}

万事大吉,回家睡觉

仔细想一下,你为啥要遥控器?

  • 电视太远了,够不到
  • 电视太贵了,坏了还得买电视

对应着

  • 电视对象你拿不到
  • 电视对象你不能操作(安全性)

那就说我使用代理模式,你总没脾气了吧,我说的是代理可以,但是无法满足我的需求,我们学习的是命令模式,还需要一些其他的骚操作

使用命令模式实现组合命令

角色

Invoker 调用者(遥控器)

Receiver 实现者(电视)

Client 来实现效果的类(我们)

Achievable 功能接口(开电源,换台,关电源)


(增加了)

Command 命令抽象接口

CloseCommand、NextChannelCommand、OpenCommand 具体实现命令

可以看出,命令模式将命令抽取成了对象

代码

Command

(可以是接口也可以是类,我这里是为了传值,所以用的抽象类还额外传递了Receiver,接口中通过setReceiver注入Receiver效果也一样)

public abstract class Command {
    protected Receiver receiver = new Receiver();

    public abstract void execute();
}

Command多种命令实现类

public class CloseCommand extends Command {

    @Override
    public void execute() {
        receiver.close();
    }
}

public class NextChannelCommand extends Command {

    private int current = 0;

    public NextChannelCommand setChannel(int channel) {
        current = channel;
        return this;
    }

    @Override
    public void execute() {
        receiver.next(current);
    }
}

public class OpenCommand extends Command {

    @Override
    public void execute() {
        receiver.open();
    }
}

Invoker

public class Invoker {

    private List<Command> commands = new ArrayList<>();

    public void add(Command command) {
        commands.add(command);
    }

    public void remove(Command command) {
        commands.remove(command);
    }

    public void execute() {
        for (Command c : commands) {
            c.execute();
        }
    }
}

Receiver不变化

实现


public class Client {

    public static void main(String[] args) {

        Invoker invoker = new Invoker();

        invoker.add(new OpenCommand());
        invoker.add(new NextChannelCommand().setChannel(2));
        invoker.add(new NextChannelCommand().setChannel(3));
        invoker.add(new CloseCommand());
        invoker.execute();

    }
}

结果

开机
换台2
换台3
关机
意外发现

说到组合命令,模版模式也可以实现组合命令,是在父类final方法中调用了其他的方法,子类实现具体操作,也可以实现命令的组合模式

想一想和命令模式区别

  • 模版模式下 组合的命令固定,如果想要修改想要修改父类或者在父类创建新的方法
  • 命令模式下 根据命令需要可以实现不同的命令组合,且不用修改父类的方法

不光如此,我们看到了,因为我们把命令生命成了对象,所以我们可以去存储他,我们又可以做到

  • 命令的恢复(返回功能)
  • 命令的存储(日志存储等)

还需要注意的是,我们调用方法实现命令的时候,全都是通过execute()方法执行的,对外隐藏了内部实现

命令模式实现返回

其他类不变

Invoker

public class Invoker {

    private List<Command> commands = new ArrayList<>();


    public void action(Command command) {
        command.execute();
        commands.add(command);
    }

    public void back() {
        if (commands.size() < 2) {
            return;
        }
        System.out.print("---返回---");
        commands.remove(commands.size() - 2).execute();
    }

    public void getInfo() {
        for (Command c : commands) {
            System.out.println(c);
        }
    }

}

实现


public class Client {

    public static void main(String[] args) {

        Invoker invoker = new Invoker();

        invoker.action(new OpenCommand());
        invoker.action(new NextChannelCommand().setChannel(2));
        invoker.action(new NextChannelCommand().setChannel(3));
        invoker.action(new NextChannelCommand().setChannel(1));
        invoker.back();
        invoker.back();
        invoker.action(new CloseCommand());
        invoker.getInfo();
    }
}

结果

开机
换台2
换台3
换台1
---返回---换台3
---返回---换台2
关机
bytetrade.io.zyhang.command.OpenCommand@14ae5a5
bytetrade.io.zyhang.command.NextChannelCommand@7f31245a
bytetrade.io.zyhang.command.CloseCommand@6d6f6e28

总结使用范围

命令模式适用于

  • 需要对行为进行处理,存储,恢复,管理
  • 多种行为的自由组合

不足

  • 容易类爆炸
  • 修改时比直接引用实现类略微繁琐

使用与否

功能简单没必要如此麻烦,设计模式本来就是为了解决问题,优化项目结构所提出的方案,至于解决问题所带来的负面效果就需要自己取舍了,符合自己需求才是最合适的解决方案,不要为了设计而设计

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值