zoukankan      html  css  js  c++  java
  • 设计模式 命令模式 之 管理智能家电

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

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

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

    需求:近期智能家电非常火热啊,未来尼玛预计冰箱都会用支付宝自己主动买东西了。,,,如果如今有电视、电脑、电灯等家电。如今须要你做个遥控器控制全部家电的开关。要求做到每一个button相应的功能供用户个性化。对于新买入家电要有非常强的扩展性。

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

    好了,以下命令模式出场,命令模式的核心就是把命令封装成类。对于命令运行者不须要知道如今运行的详细是什么命令。

    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个button
     * 
     * @author zhy
     * 
     */
    public class ControlPanel
    {
    	private static final int CONTROL_SIZE = 9;
    	private Command[] commands;
    
    	public ControlPanel()
    	{
    		commands = new Command[CONTROL_SIZE];
    		/**
    		 * 初始化全部button指向空对象
    		 */
    		for (int i = 0; i < CONTROL_SIZE; i++)
    		{
    			commands[i] = new NoCommand();
    		}
    	}
    
    	/**
    	 * 设置每一个button相应的命令
    	 * @param index
    	 * @param command
    	 */
    	public void setCommand(int index, Command command)
    	{
    		commands[index] = command;
    	}
    
    	/**
    	 * 模拟点击button
    	 * @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个button。提供了设置每一个button的功能和点击的方法,还有注意到我们使用了一个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();
    		// 为每一个button设置功能
    		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的功劳
    
    		
    
    	}
    }

    输出结果:


    能够看到随意button能够随意配置不论什么命令,再也不须要尼玛的变一下需求改代码了,随便用户怎么个性化了。事实上想白了,这里的设置我们还能够配置到一个配置文件里,全然的解耦有木有。


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

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

    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("****点击一键搞定button****");
    		controlPanel.setCommand(8, quickCommand);
    		controlPanel.keyPressed(8);


    是不是非常完美。


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

    还记得定义中提到了队列。命令模式怎样用于队列呢,比方饭店有非常多个点菜的地方,有一个做菜的地方,把点菜看作命令,做菜看作命令运行者,不断有人点菜就相当于把菜增加队列。对于做菜的仅仅管从队列里面取,取一个做一个。

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


    好了。各位留个言、点个赞算是对我的支持,多谢大家~





  • 相关阅读:
    JAAS configuration for Kafka clients
    kafka集群安全化之启用kerberos与acl
    配置两个不同kerberos认证中心的集群间的互信
    hbase-indexer官网wiki
    KSQL: Streaming SQL for Apache Kafka
    Introducing KSQL: Streaming SQL for Apache Kafka
    Sqoop import导入表时报错java.lang.ClassNotFoundException: org.json.JSONObject
    重磅开源 KSQL:用于 Apache Kafka 的流数据 SQL 引擎 2017.8.29
    sqoop与hbase导入导出数据
    用sqoop将mysql的数据导入到hive表中
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5397632.html
Copyright © 2011-2022 走看看