zoukankan      html  css  js  c++  java
  • 应对软件需求变化-命令模式的应用

    一、缘起

    在软件构建过程中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合--比如需要对行为进行“记录、撤销/重做(undo/redo)、事务”等处理,这种无法抵御变化的紧耦合是不适合的

    在这种情况下,如何将“行为请求者”与“行为实现者”解耦

    将一组行为抽象为对象,可以实现两者之间的松耦合。

    二、定义

    将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

    三、应用举例

    定义一个遥控器作为行为请求者,遥控器有多个按钮,每个按钮对应到一个命令。当按下按钮,相应命令对象的execute()方法就会被调用,其结果就是,行为实现者(例如:电灯、天花板电扇、音响)的动作被调用。

    实现遥控器:

    import java.util.*;
    
    //
    // This is the invoker
    //
    public class RemoteControlWithUndo {
        Command[] onCommands;   //遥控器处理多个开与关的命令,使用相应数组记录这些命令。另外还要处理取消命令。
        Command[] offCommands;
        Command undoCommand;
     
        public RemoteControlWithUndo() {  //在构造器中,只需实例化并初始化这两个开关数组和取消命令。
            onCommands = new Command[7];
            offCommands = new Command[7];
     
            Command noCommand = new NoCommand();
            for(int i=0;i<7;i++) {
                onCommands[i] = noCommand;
                offCommands[i] = noCommand;
            }
            undoCommand = noCommand;
        }
      
        public void setCommand(int slot, Command onCommand, Command offCommand) {
            onCommands[slot] = onCommand;  //方法有三个参数,分别是插槽的位置、开的命令、关的命令。这些命令将记录在开关数组中对应的插槽位置,以供稍后使用。
            offCommands[slot] = offCommand;
        }
     
        public void onButtonWasPushed(int slot) {
            onCommands[slot].execute();  //当按下开或关的按钮,硬件就会负责调用对应的方法。同时设置可以取消的命令。
            undoCommand = onCommands[slot];
        }
     
        public void offButtonWasPushed(int slot) {
            offCommands[slot].execute();
            undoCommand = offCommands[slot];
        }
     
        public void undoButtonWasPushed() {
            undoCommand.undo();
        }
      
        public String toString() {
            StringBuffer stringBuff = new StringBuffer();
            stringBuff.append("
    ------ Remote Control -------
    ");
            for (int i = 0; i < onCommands.length; i++) {
                stringBuff.append("[slot " + i + "] " + onCommands[i].getClass().getName()
                    + "    " + offCommands[i].getClass().getName() + "
    ");
            }
            stringBuff.append("[undo] " + undoCommand.getClass().getName() + "
    ");
            return stringBuff.toString();
        }
    }

    命令接口:

    public interface Command {
        public void execute();
        public void undo();
    }

    实现命令。开灯命令:

    public class LightOnCommand implements Command {
        Light light;
        int level;
        public LightOnCommand(Light light) {
            this.light = light;
        }
     
        public void execute() {
            level = light.getLevel();
            light.on();
        }
     
        public void undo() {
            light.dim(level);
        }
    }

    关灯命令:

    public class LightOffCommand implements Command {
        Light light;
        int level;
        public LightOffCommand(Light light) {
            this.light = light;
        }
     
        public void execute() {
            level = light.getLevel();
            light.off();
        }
     
        public void undo() {
            light.dim(level);
        }
    }

    开调光器命令:

    public class DimmerLightOnCommand implements Command {
        Light light;
        int prevLevel;
    
        public DimmerLightOnCommand(Light light) {
            this.light = light;
        }
    
        public void execute() {
            prevLevel = light.getLevel();
            light.dim(75);
        }
    
        public void undo() {
            light.dim(prevLevel);
        }
    }

    关调光器命令:

    public class DimmerLightOffCommand implements Command {
        Light light;
        int prevLevel;
    
        public DimmerLightOffCommand(Light light) {
            this.light = light;
            prevLevel = 100;
        }
    
        public void execute() {
            prevLevel = light.getLevel();
            light.off();
        }
    
        public void undo() {
            light.dim(prevLevel);
        }
    }

    吊扇开小风命令:

    public class CeilingFanLowCommand implements Command {
        CeilingFan ceilingFan;
        int prevSpeed;
      
        public CeilingFanLowCommand(CeilingFan ceilingFan) {
            this.ceilingFan = ceilingFan;
        }
     
        public void execute() {
            prevSpeed = ceilingFan.getSpeed();
            ceilingFan.low();
        }
     
        public void undo() {
            if (prevSpeed == CeilingFan.HIGH) {
                ceilingFan.high();
            } else if (prevSpeed == CeilingFan.MEDIUM) {
                ceilingFan.medium();
            } else if (prevSpeed == CeilingFan.LOW) {
                ceilingFan.low();
            } else if (prevSpeed == CeilingFan.OFF) {
                ceilingFan.off();
            }
        }
    }

    吊扇开中风命令:

    public class CeilingFanMediumCommand implements Command {
        CeilingFan ceilingFan;
        int prevSpeed;
      
        public CeilingFanMediumCommand(CeilingFan ceilingFan) {
            this.ceilingFan = ceilingFan;
        }
     
        public void execute() {
            prevSpeed = ceilingFan.getSpeed();
            ceilingFan.medium();
        }
     
        public void undo() {
            if (prevSpeed == CeilingFan.HIGH) {
                ceilingFan.high();
            } else if (prevSpeed == CeilingFan.MEDIUM) {
                ceilingFan.medium();
            } else if (prevSpeed == CeilingFan.LOW) {
                ceilingFan.low();
            } else if (prevSpeed == CeilingFan.OFF) {
                ceilingFan.off();
            }
        }
    }

    吊扇开大风命令:

    public class CeilingFanHighCommand implements Command {
        CeilingFan ceilingFan;
        int prevSpeed;
      
        public CeilingFanHighCommand(CeilingFan ceilingFan) {
            this.ceilingFan = ceilingFan;
        }
     
        public void execute() {
            prevSpeed = ceilingFan.getSpeed();
            ceilingFan.high();
        }
     
        public void undo() {
            if (prevSpeed == CeilingFan.HIGH) {
                ceilingFan.high();
            } else if (prevSpeed == CeilingFan.MEDIUM) {
                ceilingFan.medium();
            } else if (prevSpeed == CeilingFan.LOW) {
                ceilingFan.low();
            } else if (prevSpeed == CeilingFan.OFF) {
                ceilingFan.off();
            }
        }
    }

    关吊扇命令:

    public class CeilingFanOffCommand implements Command {
        CeilingFan ceilingFan;
        int prevSpeed;
      
        public CeilingFanOffCommand(CeilingFan ceilingFan) {
            this.ceilingFan = ceilingFan;
        }
     
        public void execute() {
            prevSpeed = ceilingFan.getSpeed();
            ceilingFan.off();
        }
     
        public void undo() {
            if (prevSpeed == CeilingFan.HIGH) {
                ceilingFan.high();
            } else if (prevSpeed == CeilingFan.MEDIUM) {
                ceilingFan.medium();
            } else if (prevSpeed == CeilingFan.LOW) {
                ceilingFan.low();
            } else if (prevSpeed == CeilingFan.OFF) {
                ceilingFan.off();
            }
        }
    }

    默认命令:

    public class NoCommand implements Command {
        public void execute() { }
        public void undo() { }
    }

    行为实现者。灯:

    public class Light {
        String location;
        int level;
    
        public Light(String location) {
            this.location = location;
        }
    
        public void on() {
            level = 100;
            System.out.println("Light is on");
        }
    
        public void off() {
            level = 0;
            System.out.println("Light is off");
        }
    
        public void dim(int level) {
            this.level = level;
            if (level == 0) {
                off();
            }
            else {
                System.out.println("Light is dimmed to " + level + "%");
            }
        }
    
        public int getLevel() {
            return level;
        }
    }

    吊扇:

    public class CeilingFan {
        public static final int HIGH = 3;
        public static final int MEDIUM = 2;
        public static final int LOW = 1;
        public static final int OFF = 0;
        String location;
        int speed;
     
        public CeilingFan(String location) {
            this.location = location;
            speed = OFF;
        }
      
        public void high() {
            speed = HIGH;
            System.out.println(location + " ceiling fan is on high");
        } 
     
        public void medium() {
            speed = MEDIUM;
            System.out.println(location + " ceiling fan is on medium");
        }
     
        public void low() {
            speed = LOW;
            System.out.println(location + " ceiling fan is on low");
        }
      
        public void off() {
            speed = OFF;
            System.out.println(location + " ceiling fan is off");
        }
      
        public int getSpeed() {
            return speed;
        }
    }

    遥控器客户端,测试遥控器:

    public class RemoteLoader {
     
        public static void main(String[] args) {
            RemoteControlWithUndo remoteControl = new RemoteControlWithUndo();
     
            Light livingRoomLight = new Light("Living Room");
     
            LightOnCommand livingRoomLightOn = 
                    new LightOnCommand(livingRoomLight);
            LightOffCommand livingRoomLightOff = 
                    new LightOffCommand(livingRoomLight);
     
            remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff);
     
            remoteControl.onButtonWasPushed(0);
            remoteControl.offButtonWasPushed(0);
            System.out.println(remoteControl);
            remoteControl.undoButtonWasPushed();
            remoteControl.offButtonWasPushed(0);
            remoteControl.onButtonWasPushed(0);
            System.out.println(remoteControl);
            remoteControl.undoButtonWasPushed();
    
            CeilingFan ceilingFan = new CeilingFan("Living Room");
       
            CeilingFanMediumCommand ceilingFanMedium = 
                    new CeilingFanMediumCommand(ceilingFan);
            CeilingFanHighCommand ceilingFanHigh = 
                    new CeilingFanHighCommand(ceilingFan);
            CeilingFanOffCommand ceilingFanOff = 
                    new CeilingFanOffCommand(ceilingFan);
      
            remoteControl.setCommand(0, ceilingFanMedium, ceilingFanOff);
            remoteControl.setCommand(1, ceilingFanHigh, ceilingFanOff);
       
            remoteControl.onButtonWasPushed(0);
            remoteControl.offButtonWasPushed(0);
            System.out.println(remoteControl);
            remoteControl.undoButtonWasPushed();
      
            remoteControl.onButtonWasPushed(1);
            System.out.println(remoteControl);
            remoteControl.undoButtonWasPushed();
        }
    }

    四、总结

    Command模式的根本目的在于将“行为请求者”与“行为实现者”解耦,在面向对象语言中,常见的实现手段是“将行为抽象为对象”。

    在被解耦的两者之间是通过命令对象进行沟通的

    命令对象封装了接收者和一个或一组动作。

    调用者通过调用命令对象的execute()发出请求,这会使得接收者的动作被调用。

    调用者可以接受命令当做参数,甚至在运行时动态地进行。

    命令可以支持撤销,做法是实现一个undo()方法来回到execute()被执行前的状态。

  • 相关阅读:
    转 linux下vi命令大全
    转 html5 canvas 详细使用教程
    怎么让手机网站自适应设备屏幕宽度? 转自百度经验
    转 :<meta http-equiv="X-UA-Compatible" content="IE=edge" /> 的说明
    转自haorooms :网页防止黑客跨框架攻击,及浏览器安全性想到的
    元信息标记<meta>
    Java语言的主要特性
    学习面向对象的三条主线之一 java类及类的成员
    1.5 MySQL信息源
    1.4在MySQL 8.0中添加,不建议使用或删除的服务器和状态变量及选项
  • 原文地址:https://www.cnblogs.com/windpoplar/p/13062213.html
Copyright © 2011-2022 走看看