设计模式之----命令模式

1、命令模式概要

定义: 对命令进行封装,将发出命令的责任和执行命令的责任分割开

你可以想象一个场景,你是一名在餐馆吃饭的顾客,你在菜单上写上想吃的菜,呼叫服务员帮你送给厨师

当然你完全可以自己跑去和厨师说,我要吃什么菜,但是你所坐的地方和厨房还是有一定距离的,你的每一次加菜都必须自己到厨房去,在这里你和厨师的关系是高度耦合的,因为是你和厨师说的话,厨师必须要记得你。厨师又要做菜又要把人和菜对应上,这样就会和麻烦,所以餐厅招聘了服务员,你只需要把你的需求告诉服务员,让他来帮你跑腿。这样厨师只需要埋头做菜就行了。

服务员不需要知道你需要吃什么菜,他的责任就是把菜单交给厨师,这样你和厨师之间的关系就被解耦了。

在代码中的表现就为,厨师类中不会出现有关顾客的代码,顾客类中不会出现有关厨师的代码

优点:命令模式可以很轻易的组合一些指令,而且很轻易的扩展,并且降低对象和对象之间的耦合度

缺点:会编写一些无关代码(比如上面的服务员,本质上是不需要的,但是为了代码易维护,降低耦合所添加的)

2、命令模式

Command:

定义命令的接口,声明执行的方法。

ConcreteCommand:

命令接口实现对象,是“虚”的实现;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。

Receiver:

接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。

Invoker:

要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。

Client:

创建具体的命令对象,并且设置命令对象的接收者。注意这个不是我们常规意义上的客户端,而是在组装命令对象和接收者,或许,把这个Client称为装配者会更好理解,因为真正使用命令的客户端是从Invoker来触发执行。

命令模式

3、代码举例

你现在需要编写一个遥控器上面有多个开关接口,来控制家里智能家电的开关,比如家里的电灯,电视

注意:你的遥控器应该需要有撤回指令

1)首先我们设计命令接口(Command)

public interface Command {

    void Execute();

    void Undo();

}

最基础的命令接口

2)设计具体类Receiver

public class Light {

    private String name;

    public Light(String name) {
        this.name = name;
    }

    void lightOn(){
        System.out.println(name + " Light is on");
    }

    void lightOff(){
        System.out.println(name + " Light is off");
    }
}

Light类里面有两个方法,分别是开和关

public class Tv {

    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void tvOn(){
        System.out.println(name + " Tv is on");
    }

    public void tvOff(){
        System.out.println(name + " Tv is off");
    }
}

Tv类同理

3)编写具体命令类(Concrete Command)

public class LightCommand implements Command {

    private Light light;

    public LightCommand(Light light) {
        this.light = light;
    }

    @Override
    public void Execute() {
        light.lightOn();
    }

    @Override
    public void Undo() {     //撤销操作,我们不可能关了灯再点撤销,这个操作是不合理的
        light.lightOff();
    }

}

Light类会统一执行开灯操作,撤销则为关灯

public class TvCommand implements Command {
    
    private Tv tv;

    public TvCommand(Tv tv) {
        this.tv = tv;
    }

    @Override
    public void Execute() {
        tv.tvOn();
    }

    @Override
    public void Undo() {
        tv.tvOff();
    }
}

4)命令持有类(Invoker)

public class Remoter {

    private Command[] onCommand;
    private Command[] offCommand;
    private Command undoCommand;


    public Remoter() {
        onCommand = new Command[2];
        offCommand = new Command[2];

        noCommand noCommand = new noCommand();
        for (int i = 0; i < onCommand.length; i++) {
            onCommand[i] = noCommand;
            offCommand[i] = noCommand;
        }
        undoCommand = noCommand;
    }

    public void setCommand(int slot, Command command) {
        onCommand[slot] = command;
        offCommand[slot] = command;
    }

    public void buttonPress(int slot){
        onCommand[slot].Execute();
        undoCommand = onCommand[slot];
    }

    public void Undo(){
        undoCommand.Undo();
    }
}

noCommand是空对象,设置空对象将处理null的责任转移给空对象

通过数组来确定遥控器上的按键位置

4、测试代码
public class Main {

    public static void main(String[] args) {

        //初始化命令变量
        Light Kitchen = new Light("Kitchen");
        Tv LivingRoom = new Tv("Living Room");
        LightCommand lightCommand = new LightCommand(Kitchen);
        TvCommand tvCommand = new TvCommand(LivingRoom);

        //把命令加入遥控器
        Remoter remoter = new Remoter();
        remoter.setCommand(0,lightCommand);
        remoter.setCommand(1,tvCommand);

        // Light is on
        remoter.buttonPress(0);
        // Light is off
        remoter.Undo();
        // Tv is on
        remoter.buttonPress(1);
        // Tv is off
        remoter.Undo();

    }
}

命令行输出,这样我们就完成了命令模式最基本的使用

输出结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值