zoukankan      html  css  js  c++  java
  • 设计模式学习笔记(一:命令模式)

    1.1概述

        在许多设计中,经常涉及到一个对象请求另一个对象调用其方法达到某种目的。如果请求者不希望或无法直接和被请求者打交道,即不希望或无法含有被请求者的引用,那么就可以使用命令模式。

        例如,在军队作战中,指挥官请求三连偷袭敌人,但是指挥官不希望或无法直接与三连取得联系,那么可以将该请求:“三连偷袭敌人”形成一个“作战命令”,该作战命名的核心就是“三连偷袭敌人”。只要能让该“作战命令”被执行,就会实现偷袭敌人的目的。

        命令模式的核心就是使用命令对象来封装方法调用,即将请求者的请求:“接收者调用方法”封装到命令对象的一个方法中,这样一来,当一个对象请求另一个对象调用方法来完成某项任务时,只需和命令对象打交道,即让命令对象调用封装了“请求”的那个方法即可。具体如下图1所示:

     

    图1  用命令对象封装方法调用

     

    1.2模式的结构

    命令模式的结构中包括四种角色:

    (1)接收者(Receiver):接收者是一个类的实例,该实例负责执行与请求者相关的操作。

    (2)命令接口(Command):命令是一个接口,规定了用来封装“请求”的若干个方法,比如,execute()、undo()等方法。

    (3)具体命令(ConcreteCommand):具体命令是实现命令接口的类的实例。具体命令必须实现命令接口中的方法,比如execute()方法,是该方法封装一个“请求”。

    (4)请求者(Invoker):请求者是一个包含Command接口变量的类的实例。请求者中的Command接口的变量可以存放任何具体命令的引用。请求者负责调用具体命令,让具体命令执行那些封装了“请求”的方法,比如execute()方法。

        命令模式结构的类图具体如下图2所示:

     

    图2  命令模式结构的类图

     

    1.3命令模式的优点

    (1)在命令模式中,请求者(Invoker)不直接与接收者(Receiver)交互,即请求者(Invoker)不包含接收者(Receiver)的引用,因此彻底消除了彼此之间的耦合。

    (2)命令模式满足“开-闭原则”。如果增加新的具体命令和该命令的接收者,不必修改调用者的代码,调用者就可以直接使用新的命令对象;反之,如果增加新的调用者,不必修改现有的具体命令和接收者,新增加的调用者就可以使用已有的具体命令。

    (3)由于请求者的请求被封装到了具体命令中,那么就可以将具体命令保存到持久化的媒介中,在需要的时候,重新执行这个具体命令。因此,命令模式可以记录日志。

    (4)使用命令模式可以对请求者的“请求”进行排队。每个请求都各自对应一个具体命令,因此可以按照一定顺序执行这些具体命令。

    1.4适合使用命令模式的情景

    (1)程序需要在不同的时刻指定、排列和执行请求。

    (2)程序需要提供撤销操作。

    (3)程序需要支持宏操作(宏命令是一个具体命令,不过它包含了其他具体命令的引用。即执行一个宏命令,相当于执行了许多具体命令)

    1.5命令模式的使用

         下面通过一个简单的实例,实现1.1概述中简单例子:在军队作战中,指挥官请求三连偷袭敌人。具体如下:

         首先看一下本实例构建框架具体类和1.2模式的结构中类图的对应关系,如下图3所示:

    图3  具体应用类图对应关系

         (1)接收者(Receiver)对应的CompanyArmy类代码如下:

    package com.liuzhen.one_command;
    
    public class CompanyArmy {
        //接受者执行如何偷袭敌人
        public void sneakAttack(){
            System.out.println("我们知道如何偷袭敌人,保证完成任务!!!");
        }
    }

        (2)命令接口(Command)对应的Command接口代码如下:

    package com.liuzhen.one_command;
    
    public interface Command {
    
        public abstract void execute();
    }

        (3)具体命令(ConcreteCommand)对应的ConcreteCommand类对应的代码如下:

    package com.liuzhen.one_command;
    
    public class ConcreteCommand implements Command {
    
        CompanyArmy army;   //创建接受者引用
        
        ConcreteCommand(CompanyArmy army){
            this.army = army;
        }
        //封装指挥官的请求
        public void execute(){
            army.sneakAttack();       //偷袭敌人
        }
    }

        (4)请求者(Invoker)对应的ArmySuperior类代码如下:

    package com.liuzhen.one_command;
    
    public class ArmySuperior {
    
        Command command;        //创建命令的引用
        //用来存放具体命令的引用
        public void setCommand(Command command){
            this.command = command;
        }
        //让具体命令执行execute()方法,偷袭敌人
        public void startExecuteCommand(){
            command.execute();
        }
    }

        (5)具体调用命令实现,指挥官请求三连偷袭敌人的类OneApplication类代码如下:

    package com.liuzhen.one_command;
    
    public class OneApplication {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            CompanyArmy 三连 = new CompanyArmy();     //创建接受者:三连
            Command command = new ConcreteCommand(三连);  //创建具体命令,并指定接受者为三连
            ArmySuperior 指挥官 = new ArmySuperior();  //创建请求者:指挥官
            指挥官.setCommand(command);   //指挥者请求命令:三连偷袭敌人
            指挥官.startExecuteCommand();  //指挥官确定执行命令:三连偷袭敌人
    
        }
    
    }

    运行结果如下图4:

    图4  运行结果

    参考资料:

          1.Java设计模式/耿祥义,张跃平著.——北京:清华大学出版社,2009.5

  • 相关阅读:
    UVA 1001 Say Cheese
    UVa 821 Page Hopping
    UVA 1569 Multiple
    UVA 1395 Slim Span
    UVA 12219 Common Subexpression Elimination
    UVA 246 10-20-30
    Mysql基本操作
    浅析关键字static
    面试回答技巧
    五个程序员好习惯
  • 原文地址:https://www.cnblogs.com/liuzhen1995/p/5971708.html
Copyright © 2011-2022 走看看