zoukankan      html  css  js  c++  java
  • Java之命令模式(Command Pattern)

    1.概念

      将来自客户端的请求传入一个对象,从而使你可用不同的请求对客户进行参数化。用于“行为请求者”与“行为实现者”解耦,可实现二者之间的松耦合,以便适应变化。分离变化与不变的因素。

       在面向对象的程序设计中,一个对象调用另一个对象,一般情况下的调用过程是:创建目标对象实例;设置调用参数;调用目标对象的方法。

    但在有些情况下有必要使用一个专门的类对这种调用过程加以封装,我们把这种专门的类称作command类。

    Command模式可应用于
    a)整个调用过程比较繁杂,或者存在多处这种调用。这时,使用Command类对该调用加以封装,便于功能的再利用。
    b)调用前后需要对调用参数进行某些处理。
    c)调用前后需要进行某些额外处理,比如日志,缓存,记录历史操作等。

    Command模式有如下效果:
    a)将调用操作的对象和知道如何实现该操作的对象解耦。
    b)Command是头等对象。他们可以像其他对象一样被操作和扩展。
    c)你可将多个命令装配成一个符合命令。
    d)增加新的Command很容易,因为这无需改变现有的类。

    2.UML

    3.代码

    复制代码
    public interface Command {
    public void execute();
    }


    public class ConcreteCommand implements Command {

    private Receiver receiver = null;
    private String state;

    public ConcreteCommand(Receiver receiver){
    this.receiver = receiver;
    }
    public void execute() {
    receiver.action();
    }
    }


    public class Receiver {
    public void action(){
    //真正执行命令操作的功能代码
    }
    }


    public class Invoker {
    private Command command = null;

    public void setCommand(Command command) {
    this.command = command;
    }

    public void runCommand() {
    command.execute();
    }
    }

    public class Client {
    public void assemble(){
    //创建接收者
    Receiver receiver = new Receiver();
    //创建命令对象,设定它的接收者
    Command command = new ConcreteCommand(receiver);
    //创建Invoker,把命令对象设置进去
    Invoker invoker = new Invoker();
    invoker.setCommand(command);
    }
    }
    复制代码
    复制代码
    下面给个例子,是模拟对电视机的操作有开机、关机、换台命令。代码如下

    //命令接收者
    public class Tv {
      public int currentChannel = 0;

      public void turnOn() {
       System.out.println("The televisino is on.");
      }

      public void turnOff() {
       System.out.println("The television is off.");
      }

      public void changeChannel(int channel) {
       this.currentChannel = channel;
       System.out.println("Now TV channel is " + channel);
      }
    }

    //执行命令的接口
    public interface Command {
      void execute();
    }

    //开机命令
    public class CommandOn implements Command {
      private Tv myTv;

      public CommandOn(Tv tv) {
       myTv = tv;
      }

      public void execute() {
       myTv.turnOn();
      }
    }

    //关机命令
    public class CommandOff implements Command {
      private Tv myTv;

      public CommandOff(Tv tv) {
       myTv = tv;
      }

      public void execute() {
       myTv.turnOff();
      }
    }

    //频道切换命令
    public class CommandChange implements Command {
      private Tv myTv;

      private int channel;

      public CommandChange(Tv tv, int channel) {
       myTv = tv;
       this.channel = channel;
      }

      public void execute() {
       myTv.changeChannel(channel);
      }
    }

    //可以看作是遥控器吧
    public class Control {
      private Command onCommand, offCommand, changeChannel;

      public Control(Command on, Command off, Command channel) {
       onCommand = on;
       offCommand = off;
       changeChannel = channel;
      }

      public void turnOn() {
       onCommand.execute();
      }

      public void turnOff() {
       offCommand.execute();
      }

      public void changeChannel() {
       changeChannel.execute();
      }
    }

    //测试类
    public class Client {
      public static void main(String[] args) {
       // 命令接收者
       Tv myTv = new Tv();
       // 开机命令
       CommandOn on = new CommandOn(myTv);
       // 关机命令
       CommandOff off = new CommandOff(myTv);
       // 频道切换命令
       CommandChange channel = new CommandChange(myTv, 2);
       // 命令控制对象
       Control control = new Control(on, off, channel);

       // 开机
       control.turnOn();
       // 切换频道
       control.changeChannel();
       // 关机
       control.turnOff();
      }
    }


    执行结果为:
    The televisino is on.
    Now TV channel is 2
    The television is off.
    复制代码

    4.应用场景

    在下面的情况下应当考虑使用命令模式:

    1)使用命令模式作为"CallBack"在面向对象系统中的替代。"CallBack"讲的便是先将一个函数登记上,然后在以后调用此函数。

    2)需要在不同的时间指定请求、将请求排队。一个命令对象和原先的请求发出者可以有不同的生命期。换言之,原先的请求发出者可能已经不在了,而命令对象本身仍然是活动的。这时命令的接收者可以是在本地,也可以在网络的另外一个地址。命令对象可以在串形化之后传送到另外一台机器上去。

    3)系统需要支持命令的撤消(undo)。命令对象可以把状态存储起来,等到客户端需要撤销命令所产生的效果时,可以调用undo()方法,把命令所产生的效果撤销掉。命令对象还可以提供redo()方法,以供客户端在需要时,再重新实施命令效果。

    4)如果一个系统要将系统中所有的数据更新到日志里,以便在系统崩溃时,可以根据日志里读回所有的数据更新命令,重新调用Execute()方法一条一条执行这些命令,从而恢复系统在崩溃前所做的数据更新。

  • 相关阅读:
    leetcode 48. Rotate Image
    leetcode 203. Remove Linked List Elements 、83. Remove Duplicates from Sorted List 、82. Remove Duplicates from Sorted List II(剑指offer57 删除链表中重复的结点) 、26/80. Remove Duplicates from Sorted ArrayI、II
    leetcode 263. Ugly Number 、264. Ugly Number II 、313. Super Ugly Number 、204. Count Primes
    leetcode 58. Length of Last Word
    安卓操作的一些问题解决
    leetcode 378. Kth Smallest Element in a Sorted Matrix
    android studio Gradle Build速度加快方法
    禁用gridview,listview回弹或下拉悬停
    Android Studio找不到FragmentActivity类
    安卓获取ListView、GridView等滚动的距离(高度)
  • 原文地址:https://www.cnblogs.com/makeryan/p/2498281.html
Copyright © 2011-2022 走看看