java设计模式学习之命令模式(更简单的理解设计模式)

本文深入解析命令模式的设计理念,展示如何通过将请求封装为对象,实现请求者与执行者的解耦,提高软件系统的灵活性和可扩展性。通过具体示例,讲解传统OOP方式与命令模式实现的区别,以及命令模式在实际项目中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传统OOP方式:

控制器

package com.java.jikexueyuan.commandmode;

/**
 * 定义一个遥控器接口
 */
public interface Control {

   /**
    *  开
    * @param slot
    */
   public void onButton(int slot);

   /**
    * 关
    * @param slot
    */
   public void offButton(int slot);

   /**
    * 回退
    */
   public void undoButton();
}


实现
package com.java.jikexueyuan.commandmode;

import com.java.jikexueyuan.commandmode.device.Light;
import com.java.jikexueyuan.commandmode.device.Stereo;

/**
 * 模拟一个遥控器 可以操作传递进来的灯和收音机
 *  直接设定每一个位置的功能
 *  *0 *3
 *  *1 *4
 *  *2 *5
 *
 *  虽然完成了按指定的按钮 可以进行相应的操作
 *  但是 我们的控制器和我们的命令直接耦合死了。如果新增一个家电,也想要被遥控器操作,那么就需要修改我们的构造方法,成员变量。成员方法
 *
 *
 */
public class TraditionControl implements Control {
    Light light;
    Stereo stereo;

    public TraditionControl(Light light, Stereo stereo) {
        this.light = light;
        this.stereo = stereo;
    }

    @Override
    public void onButton(int slot) {
        // TODO Auto-generated method stub
        switch (slot) {
            case 0:
                light.On();
                break;
            case 1:
                stereo.On();
                break;
            case 2:
                int vol = stereo.GetVol();
                if (vol < 11) {
                    stereo.SetVol(++vol);
                }
                break;
        }
    }

    @Override
    public void offButton(int slot) {
        // TODO Auto-generated method stub
        switch (slot) {
            case 0:
                light.Off();
                break;
            case 1:
                stereo.Off();
                break;
            case 2:
                int vol = stereo.GetVol();
                if (vol > 0) {
                    stereo.SetVol(--vol);
                }
                break;
        }
    }

    @Override
    public void undoButton() {
        // TODO Auto-generated method stub

    }


}

家具模拟

package com.java.jikexueyuan.commandmode.device;

/**
 * 模拟一个灯  可根据传递不同的参数 操作不同的灯
 */
public class Light {

    String loc = "";

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

    public void On() {

        System.out.println(loc + " On");
    }

    public void Off() {

        System.out.println(loc + " Off");
    }

}

package com.java.jikexueyuan.commandmode.device;

/**
 * 模拟一个收音机
 *  有开关,设置cd 设置声音 获取声音的功能
 */
public class Stereo {
   static int volume = 0;

   public void On() {
      System.out.println("Stereo On");
   }

   public void Off() {
      System.out.println("Stereo Off");
   }

   public void SetCd() {
      System.out.println("Stereo SetCd");
   }

   public void SetVol(int vol) {
      volume = vol;
      System.out.println("Stereo volume=" + volume);
   }

   public int GetVol() {
      return volume;
   }

   public void Start() {
      System.out.println("Stereo Start");
   }
}

Demo

package com.java.jikexueyuan.commandmode;

import com.java.jikexueyuan.commandmode.device.Light;
import com.java.jikexueyuan.commandmode.device.Stereo;

public class ControlTest {
   public static void main(String[] args) {
      Control ctl;
      Light light = new Light("Bedroom");
      Stereo stereo = new Stereo();
      ctl = new TraditionControl(light, stereo);

      ctl.onButton(0);
      ctl.offButton(0);
      ctl.onButton(1);
      ctl.onButton(2);
      ctl.offButton(2);

      ctl.offButton(1);
   }
}

命令模式实现:

命令接口

package com.java.jikexueyuan.commandmode.command;

/**
 * 将我们的每一条命令都封装为对象,控制器不直接执行具体的命令,而是操作命令接口的方法,
 * 将具体操作什么样的命令交给接口的实现类来决定 ,从而实现了我们控制器和命令的解耦合。
 */
public interface Command {
   /**
    * 定义执行接口
    */
   public void execute();

   /**
    * 定义撤销接口
    */
   public void undo();
}

基础命令

package com.java.jikexueyuan.commandmode.command;

import com.java.jikexueyuan.commandmode.device.Light;

/**
 *  * 定义关闭灯的command命令。并且构造方法中传递具体需要关闭的灯名称
 *  * 关闭灯所对应的回退undo 为打开灯。在undo中调用相应的回退命令方法
 */
public class LightOffCommand implements Command {
   private Light light;
   public LightOffCommand(Light light)
   {
      this.light=light;
   }
   @Override
   public void execute() {
      // TODO Auto-generated method stub
      light.Off();
   }

   @Override
   public void undo() {
      // TODO Auto-generated method stub
      light.On();
   }

}

package com.java.jikexueyuan.commandmode.command;

import com.java.jikexueyuan.commandmode.device.Light;

/**
 * 定义打开灯的command命令。并且构造方法中传递具体需要打开的灯名称
 * 打开灯所对应的回退undo 为关闭灯。在undo中调用相应的回退命令方法
 *
 */
public class LightOnCommand implements Command {
   private Light light;
   
   public LightOnCommand(Light light)
   {
      this.light=light;
      
   }
   @Override
   public void execute() {
      // TODO Auto-generated method stub
      light.On();
   }

   @Override
   public void undo() {
      // TODO Auto-generated method stub
      light.Off();
   }

}

package com.java.jikexueyuan.commandmode.command;

import com.java.jikexueyuan.commandmode.device.Stereo;

/**
 * 加声音的命令以及回退
 */
public class StereoAddVolCommand implements Command {
    private Stereo setreo;

    public StereoAddVolCommand(Stereo setreo) {
        this.setreo = setreo;
    }

    @Override
    public void execute() {
        // TODO Auto-generated method stub
        int vol = setreo.GetVol();
        if (vol < 11) {
            setreo.SetVol(++vol);
        }

    }

    @Override
    public void undo() {
        // TODO Auto-generated method stub
        int vol = setreo.GetVol();
        if (vol > 0) {
            setreo.SetVol(--vol);
        }

    }

}

package com.java.jikexueyuan.commandmode.command;

import com.java.jikexueyuan.commandmode.device.Stereo;

/**
 * 关闭收音机命令
 */
public class StereoOffCommand implements Command {
   private Stereo setreo;
   public StereoOffCommand(Stereo setreo)
   {
      this.setreo=setreo;
   }
   
   @Override
   public void execute() {
      // TODO Auto-generated method stub
      setreo.Off();
   }

   @Override
   public void undo() {
      // TODO Auto-generated method stub
      setreo.On();
      setreo.SetCd();
   }

}


package com.java.jikexueyuan.commandmode.command;

import com.java.jikexueyuan.commandmode.device.Stereo;

/**
 * 打开收音机的命令。在execute 执行时。可以同时进行多种操作。合并为同一命令
 */
public class StereoOnCommand implements Command {
   private Stereo setreo;
   public StereoOnCommand(Stereo setreo)
   {
      this.setreo=setreo;
   }
   
   @Override
   public void execute() {
      // TODO Auto-generated method stub
      setreo.On();
      setreo.SetCd();
      
   }

   @Override
   public void undo() {
      // TODO Auto-generated method stub
      setreo.Off();
   }

}

package com.java.jikexueyuan.commandmode.command;

import com.java.jikexueyuan.commandmode.device.Stereo;

public class StereoSubVolCommand implements Command {
   private Stereo setreo;
   public StereoSubVolCommand(Stereo setreo)
   {
      this.setreo=setreo;
   }
   
   @Override
   public void execute() {
      // TODO Auto-generated method stub
   int vol=   setreo.GetVol();
   if(vol>0)
   {
      setreo.SetVol(--vol);
   }
      
   }

   @Override
   public void undo() {
      // TODO Auto-generated method stub
   int vol=   setreo.GetVol();
   if(vol<11)
   {
      setreo.SetVol(++vol);
   }
      
   }

}

初始化时什么都不操作的命令

package com.java.jikexueyuan.commandmode.command;

/**
 * 定义一个NoCommand实现,当我们控制器的某项按钮没有指定相应的命令时,进行空实现,有需要的时候再进行设置
 */
public class NoCommand implements Command {

   @Override
   public void execute() {
      // TODO Auto-generated method stub

   }

   @Override
   public void undo() {
      // TODO Auto-generated method stub

   }

}

宏命令(批量操作命令)

package com.java.jikexueyuan.commandmode.command;

/**
 * 宏命令 自定义一组命令集合,可同时执行,例如,同时打开卧室灯,厨房灯。 同时关闭等等
 * 控制器在进行操作时 并不在乎我们所传递的为宏命令还是单一命令。他都会逐个的进行操作
 */
public class MarcoCommand implements Command {

    private Command[] commands;

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

    @Override
    public void execute() {
        // TODO Auto-generated method stub
        for (int i = 0, len = commands.length; i < len; i++) {
            commands[i].execute();
        }
    }

    @Override
    public void undo() {
        // TODO Auto-generated method stub
        for (int i = commands.length - 1; i >= 0; i--) {
            commands[i].undo();

        }
    }

}

控制器实现

package com.java.jikexueyuan.commandmode.command;

import java.util.Stack;

import com.java.jikexueyuan.commandmode.Control;
import com.java.jikexueyuan.commandmode.device.Light;
import com.java.jikexueyuan.commandmode.device.Stereo;

/**
 * 定义控制器
 *  *on *off
 *  *1  *1
 *  *2  *2
 *  *2  *2
 *  *2  *2
 *  *2  *2
 *
 */
public class CommandModeControl implements Control {
    private Command[] onCommands;
    private Command[] offCommands;
    /**
     * 创建命令栈
     */
    private Stack<Command> stack = new Stack<Command>();

    /**
     * 构造方法中初始化控制器的命令。将所有的命令设置为noCommand (即按了没反应)
     * 初始化五个onCommand 五个offCommand
     */
    public CommandModeControl() {
        onCommands = new Command[5];
        offCommands = new Command[5];

        Command noCommand = new NoCommand();

        for (int i = 0, len = onCommands.length; i < len; i++) {
            onCommands[i] = noCommand;
            offCommands[i] = noCommand;
        }

    }

    /**
     * 给指定的一排按钮添加响应的on命令 off命令
     * @param slot
     * @param onCommand
     * @param offCommand
     */
    public void setCommand(int slot, Command onCommand, Command offCommand) {
        onCommands[slot] = onCommand;
        offCommands[slot] = offCommand;
    }

    /**
     * 执行指定行上的开按钮 并且通过栈记录相应的操作
     * @param slot
     */
    @Override
    public void onButton(int slot) {
        onCommands[slot].execute();
        stack.push(onCommands[slot]);
    }

    /**
     * 执行指定行上的关按钮 并且通过栈记录相应的操作
     * @param slot
     */
    @Override
    public void offButton(int slot) {

        offCommands[slot].execute();
        stack.push(offCommands[slot]);
    }

    /**
     * 执行回退操作
     */
    @Override
    public void undoButton() {
        // TODO Auto-generated method stub
        stack.pop().undo();
    }

}

Demo

package com.java.jikexueyuan.commandmode.command;

import com.java.jikexueyuan.commandmode.Control;
import com.java.jikexueyuan.commandmode.TraditionControl;
import com.java.jikexueyuan.commandmode.device.Light;
import com.java.jikexueyuan.commandmode.device.Stereo;

public class ControlTest {

   public static void main(String[] args) {
      // 定义一个控制器
      CommandModeControl control = new CommandModeControl();
      /**
       * 定义一组宏命令
       */
      MarcoCommand onmarco,offmarco;

      /**
       * 定义一些灯
       */
      Light bedroomlight = new Light("BedRoom");
      Light kitchlight = new Light("Kitch");

      /**
       * 定义一个收音机
       */
      Stereo stereo = new Stereo();


      /**
       * 创建开灯 关灯 指令 (厨房--卧室)
       */
      LightOnCommand bedroomlighton = new LightOnCommand(bedroomlight);
      LightOffCommand bedroomlightoff = new LightOffCommand(bedroomlight);
      LightOnCommand kitchlighton = new LightOnCommand(kitchlight);
      LightOffCommand kitchlightoff = new LightOffCommand(kitchlight);

      /**
       * 将开关灯指令 设置为宏命令
       */
       Command[] oncommands={bedroomlighton,kitchlighton};
       Command[] offcommands={bedroomlightoff,kitchlightoff};
         
      onmarco=new MarcoCommand(oncommands);
      offmarco=new MarcoCommand(offcommands);

      /**
       * 定义收音机指令
       */
      StereoOnCommand stereoOn = new StereoOnCommand(stereo);
      StereoOffCommand stereoOff = new StereoOffCommand(stereo);
      StereoAddVolCommand stereoaddvol = new StereoAddVolCommand(stereo);
      StereoSubVolCommand stereosubvol = new StereoSubVolCommand(stereo);

      /**
       * 在指定的位置设置相关命令
       */
      control.setCommand(0, bedroomlighton, bedroomlightoff);
      control.setCommand(1, kitchlighton, kitchlightoff);
      control.setCommand(2, stereoOn, stereoOff);
      control.setCommand(3, stereoaddvol, stereosubvol);
      control.setCommand(4, onmarco, offmarco);

      /**
       * 操作控制器执行命令
       */
      control.onButton(0);
      control.undoButton();
      //control.offButton(0);
      control.onButton(1);
      control.offButton(1);
      control.onButton(2);
      control.onButton(3);
            
      control.offButton(3);
      control.undoButton();
      control.offButton(2);
      control.undoButton();
      control.onButton(4);
      control.offButton(4);
   }

   /**
    * 命令模式:将请求、命令、动作等封装成对象,这样可以让项目使用这些对象来
    * 参数化其他对象。使得命令的请求者和执行者解耦
    *
    *
    */

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值