设计模式 命令模式 之 管理智能家电

继续设计模式哈,今天带来命令模式,二话不说,先看定义:

定义:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。

这尼玛定义,看得人蛋疼,看不明白要淡定,我稍微简化一下:将请求封装成对象,将动作请求者和动作执行者解耦。好了,直接用例子来说明。

需求:最近智能家电很火热啊,未来尼玛估计冰箱都会用支付宝自动买东西了,,,,假设现在有电视、电脑、电灯等家电,现在需要你做个遥控器控制所有家电的开关,要求做到每个按钮对应的功能供用户个性化,对于新买入家电要有非常强的扩展性。

这个需求一看,尼玛要是没有什么个性化、扩展性还好说啊,直接针对每个遥控器的按钮onClick,然后在里面把代码写死就搞定了,但是个性化怎么整,还要有扩展性。。。

好了,下面命令模式出场,命令模式的核心就是把命令封装成类,对于命令执行者不需要知道现在执行的具体是什么命令。

1、首先看下我们拥有的家电的API:

package com.zhy.pattern.command;
/**
 * 门
 * @author zhy
 *
 */
public class Door
{
    public void open()
    {
        System.out.println("打开门");
    }

    public void close()
    {
        System.out.println("关闭门");
    }

}
package com.zhy.pattern.command;

/**
 * 电灯
 * @author zhy
 *
 */
public class Light
{
    public void on()
    {
        System.out.println("打开电灯");
    }

    public void off()
    {
        System.out.println("关闭电灯");
    }
}
package com.zhy.pattern.command;
/**
 * 电脑
 * @author zhy
 *
 */
public class Computer
{
    public void on()
    {
        System.out.println("打开电脑");
    }

    public void off()
    {
        System.out.println("关闭电脑");
    }
}

看来我们有电灯、电脑、和门,并且开关的接口的设计好了。接下来看如何把命令封装成类:

package com.zhy.pattern.command;

public interface Command
{
    public void execute();
}
package com.zhy.pattern.command;

/**
 * 关闭电灯的命令
 * @author zhy
 *
 */
public class LightOffCommond implements Command
{
    private Light light ; 

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

    @Override
    public void execute()
    {
        light.off();
    }

}
package com.zhy.pattern.command;

/**
 * 打开电灯的命令
 * @author zhy
 *
 */
public class LightOnCommond implements Command
{
    private Light light ; 

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

    @Override
    public void execute()
    {
        light.on();
    }

}
package com.zhy.pattern.command;

/**
 * 开电脑的命令
 * @author zhy
 *
 */
public class ComputerOnCommond implements Command
{
    private Computer computer ; 

    public ComputerOnCommond( Computer computer)
    {
        this.computer = computer;
    }

    @Override
    public void execute()
    {
        computer.on();
    }

}
package com.zhy.pattern.command;

/**
 * 关电脑的命令
 * @author zhy
 *
 */
public class ComputerOffCommond implements Command
{
    private Computer computer ; 

    public ComputerOffCommond( Computer computer)
    {
        this.computer = computer;
    }

    @Override
    public void execute()
    {
        computer.off();
    }

}

好了,不贴那么多了,既然有很多命令,按照设计原则,我们肯定有个超类型的Command,然后各个子类,看我们把每个命令(请求)都封装成类了。接下来看我们的遥控器。

package com.zhy.pattern.command;

/**
 * 控制器面板,一共有9个按钮
 *
 * @author zhy
 *
 */
public class ControlPanel
{
    private static final int CONTROL_SIZE = 9;
    private Command[] commands;

    public ControlPanel()
    {
        commands = new Command[CONTROL_SIZE];
        /**
         * 初始化所有按钮指向空对象
         */
        for (int i = 0; i < CONTROL_SIZE; i++)
        {
            commands[i] = new NoCommand();
        }
    }

    /**
     * 设置每个按钮对应的命令
     * @param index
     * @param command
     */
    public void setCommand(int index, Command command)
    {
        commands[index] = command;
    }

    /**
     * 模拟点击按钮
     * @param index
     */
    public void keyPressed(int index)
    {
        commands[index].execute();
    }

}
package com.zhy.pattern.command;

/**
 * @author zhy
 *
 */
public class NoCommand implements Command
{
    @Override
    public void execute()
    {

    }

}

注意看到我们的遥控器有9个按钮,提供了设置每个按钮的功能和点击的方法,还有注意到我们使用了一个NoCommand对象,叫做空对象,这个对象的好处就是,我们不用执行前都判断个if(!=null),并且提供了一致的操作。

最后测试一下代码:

package com.zhy.pattern.command;

public class Test
{
    public static void main(String[] args)
    {
        /**
         * 三个家电
         */
        Light light = new Light();
        Door door = new Door();
        Computer computer = new Computer();
        /**
         * 一个控制器,假设是我们的app主界面
         */
        ControlPanel controlPanel = new ControlPanel();
        // 为每个按钮设置功能
        controlPanel.setCommand(0, new LightOnCommond(light));
        controlPanel.setCommand(1, new LightOffCommond(light));
        controlPanel.setCommand(2, new ComputerOnCommond(computer));
        controlPanel.setCommand(3, new ComputerOffCommond(computer));
        controlPanel.setCommand(4, new DoorOnCommond(door));
        controlPanel.setCommand(5, new DoorOffCommond(door));

        // 模拟点击
        controlPanel.keyPressed(0);
        controlPanel.keyPressed(2);
        controlPanel.keyPressed(3);
        controlPanel.keyPressed(4);
        controlPanel.keyPressed(5);
        controlPanel.keyPressed(8);// 这个没有指定,但是不会出任何问题,我们的NoCommand的功劳

    }
}

输出结果:

可以看到任意按钮可以随意配置任何命令,再也不需要尼玛的变一下需求改代码了,随便用户怎么个性化了。其实想白了,这里的设置我们还可以配置到一个配置文件中,完全的解耦有木有。

好了,用户对于这个按钮可能还不是太满意,用户希望夜深人静的时候,能够提供个按钮直接关门、关灯、开电脑,,,,大家懂的,,,我们稍微修改下代码,满足他

定义一个命令,用户干一些列的事,可配置,且与原来的命令保持接口一致:

package com.zhy.pattern.command;

/**
 * 定义一个命令,可以干一系列的事情
 *
 * @author zhy
 *
 */
public class QuickCommand implements Command
{
    private Command[] commands;

    public QuickCommand(Command[] commands)
    {
        this.commands = commands;
    }

    @Override
    public void execute()
    {
        for (int i = 0; i < commands.length; i++)
        {
            commands[i].execute();
        }
    }

}

好了,已经满足屌丝的需求了。我们测试看看。

// 定义一键搞定模式
        QuickCommand quickCommand = new QuickCommand(new Command[] { new DoorOffCommond(door),
                new LightOffCommond(light), new ComputerOnCommond(computer) });
        System.out.println("****点击一键搞定按钮****");
        controlPanel.setCommand(8, quickCommand);
        controlPanel.keyPressed(8);

是不是很完美。

最后,继续来谈谈命令模式,命令模式就是把命令封装成对象,然后将动作请求者与动作执行者完全解耦,上例中遥控器的按钮和电器一毛钱关系都没吧。

还记得定义中提到了队列,命令模式如何用于队列呢,比如饭店有很多个点菜的地方,有一个做菜的地方,把点菜看作命令,做菜看作命令执行者,不断有人点菜就相当于把菜加入队列,对于做菜的只管从队列里面取,取一个做一个。

定义中还提到了日志,日志一般用于记录用户行为,或者在异常时恢复时用的,比如每个命令现在包含两个方法,一个执行execute,一个undo(上例中为了方便大家理解,没有写undo),我们可以把用户所有命令调用保存到日志中,比如用户操作不当了,电器异常了,只需要把日志中所有的命令拿出来执行一遍undo就完全恢复了,是吧,就是这么个意思。

时间: 2024-11-08 18:57:58

设计模式 命令模式 之 管理智能家电的相关文章

设计模式 - 命令模式(command pattern) 具体解释

命令模式(command pattern) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 命令模式(command pattern) : 将请求封装成对象, 以便使用不同的请求\队列\日志来參数化其它对象. 命令模式也能够支持撤销操作. 简单的命令模式的实现: 1. 详细的类, 每个类都有特定的方法: /** * @time 2014年6月9日 */ package command; /** * @author C.L.Wang * */ publ

设计模式 - 命令模式(command pattern) 详解

命令模式(command pattern) 详解 本文地址: http://blog.csdn.net/caroline_wendy 命令模式: 将请求封装成对象, 以便使用不同的请求\队列\日志来参数化其他对象. 命令模式也支持可撤销操作. 命令模式: 调用者(Invoker); 命令(Command): 可执行方法(execute), 具体命令(Concrete Command); 接受者(Receiver): 调用命令(Set Command); 具体方法: 1. 具体对象. /** *

设计模式 - 命令模式(command pattern) 多命令 详解

命令模式(command pattern) 多命令 详解 本文地址: http://blog.csdn.net/caroline_wendy 参考命令模式: http://blog.csdn.net/caroline_wendy/article/details/31379977 具体步骤: 1. 多命令, 把未使用的命令, 初始化为空对象(NoCommand), 根据参数(slot), 选择输出命令. /** * @time 2014年6月16日 */ package command; /**

设计模式 - 命令模式(command pattern) 撤销(undo) 详解

命令模式(command pattern) 撤销(undo) 详解 本文地址: http://blog.csdn.net/caroline_wendy 参考命令模式: http://blog.csdn.net/caroline_wendy/article/details/31379977 命令模式可以用于执行撤销(undo)操作. 具体方法: 1. 对象类中需要保存状态, 如level. package command; public class CeilingFan { String loca

设计模式 - 命令模式(command pattern) 宏命令(macro command) 详解

命令模式(command pattern) 宏命令(macro command) 详解 本文地址: http://blog.csdn.net/caroline_wendy 参考: 命名模式(撤销): http://blog.csdn.net/caroline_wendy/article/details/31419101 命令模式可以执行宏命令(macro command), 即多个命令的组合操作. 具体方法:  1. 其余代码与命令(撤销)一致 2. 添加宏命令(macro command),

小菜学设计模式——命令模式

背景 外面小摊与店面的比较,你就会发现,店面似乎更加容易管理,为什么呢?因为在客户与老板自己新增了很多员工,这些员工各司其职,所以井然有序,事情才会高效进行.这里有个重要的设计模式就是命令模式. 1.使用意图 在软件系统中,"行为请求者"与"行为实现者"通常呈现一种"紧耦合".但在某些场合,比如要对行为进行"记录.撤销/重做.事务"等处理,这种无法抵御变化的紧耦合是不合适的.在这种情况下,如何将"行为请求者"

设计模式--命令模式(Command)

基本概念: Command模式也叫命令模式 ,是行为设计模式的一种.Command模式通过被称为Command的类封装了对目标对象的调用行为以及调用参数,命令模式将方法调用给封装起来了. 命令模式的几个角色: Command: 抽象命令类 ConcreteCommand: 具体命令类 Invoker: 调用者 Receiver: 接收者 Client:客户类 命令模式的优缺点: 优点 1. 降低了系统耦合度 2. 新的命令可以很容易添加到系统中去. 缺点 使用命令模式可能会导致某些系统有过多的具

读书笔记之设计模式-命令模式

行为型:Command(命令模式) 命令模式: 目的:其实一般设计模式就是为了解耦.也没什么特别的,命令模式实际上就是将命令的请求者和命令的执行者解耦. 白话:领导说了,让把这个月的项目计划压缩到三个礼拜完成,还说了:"不管你用什么办法".这句“不管你用什么办法”就是我们所说的解耦.我不需要关心你怎么去做,我只要你能实现我想达到的目的. 模式结构:一般包含下面几个部分. Client:客户 Invoker:命令触发者 Command:命令 ConcreteCommand:具体命令实现

iOS设计模式 - 命令模式

命令模式 前言: 命令对象封装了如何对目标执行指令的信息,因此客户端或调用者不必了解目标的任何细节,却仍可以对他执行任何已有的操作.通过把请求封装成对象,客 户端可 以把它参数化并置入队列或日志中,也能够支持可撤销操作.命令对象将一个或多个动作绑定到特定的接收器.命令模式消除了作为对象的动作和执行它的接收器之 间的绑定. 正文内容大纲: 1.电视机.遥控器与接收器之间的关系2.改变一个视图的明暗程度(未使用命令模式)3.命令模式介绍4.改变一个视图的明暗程度(使用命令模式)5.附录 命令模式 1