zoukankan      html  css  js  c++  java
  • 16、设计模式-行为型模式-命令模式

    命令模式(请求发送者与接收者解耦)

    在软件开发中,我们经常需要向某些对象发送请求(调用其中的某个或某些方法),但是并
    不知道请求的接收者是谁,也不知道被请求的操作是哪个,此时,我们特别希望能够以一种
    松耦合的方式来设计软件,使得请求发送者与请求接收者能够消除彼此之间的耦合,让对象
    之间的调用关系更加灵活,可以灵活地指定请求接收者以及被请求的操作。命令模式为此类
    问题提供了一个较为完美的解决方案

    命令模式可以将请求发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发
    送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。

    定义:

    将一个请求封装为一个对象,从而让我们可用不同的请求对客户进行参数化

    对请求排队或者记录请求日志,以及支持可撤销的操作。

    命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。

    命令模式的核心在于引入了命令类,通过命令类来降低发送者和接收者的耦合度,请求发送
    者只需指定一个命令对象,再通过命令对象来调用请求接收者的处理方法

    Command(抽象命令类):抽象命令类一般是一个抽象类或接口,在其中声明了用于执行
    请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作。
     

    ConcreteCommand(具体命令类):具体命令类是抽象命令类的子类,实现了在抽象命令类
    中声明的方法,它对应具体的接收者对象,将接收者对象的动作绑定其中。在实现execute()方
    法时,将调用接收者对象的相关操作(Action)。
     

    Invoker(调用者):调用者即请求发送者,它通过命令对象来执行请求。一个调用者并不
    需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联关系。在程序运行时可以
    将一个具体命令对象注入其中,再调用具体命令对象的execute()方法,从而实现间接调用请求
    接收者的相关操作。

    Receiver(接收者):接收者执行与请求相关的操作,它具体实现对请求的业务处理。

    命令模式的本质是对请求进行封装,一个请求对应于一个命令,将发出命令的责任和执行命
    令的责任分割开。每一个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收
    的一方收到请求,并执行相应的操作

    命令模式允许请求的一方和接收的一方独立开来,使
    得请求的一方不必知道接收请求的一方的接口,更不必知道请求如何被接收、操作是否被执
    行、何时被执行,以及是怎么被执行的。

    命令模式的关键在于引入了抽象命令类,请求发送者针对抽象命令类编程,只有实现了抽象
    命令类的具体命令才与请求接收者相关联。

    事例:

    抽象命令类

    abstract class Command {
        public abstract void execute();
    }

    具体命令类

    public class MinimizeCommand extends Command {
    
        private WindowHanlder whObj; //维持对请求接收者的引用
        public MinimizeCommand() {
            whObj = new WindowHanlder();
        }
        //命令执行方法,将调用请求接收者的业务方法
        public void execute() {
            whObj.minimize();
        }
    }
    public class HelpCommand extends Command {
    
        private HelpHandler hhObj; //维持对请求接收者的引用
        public HelpCommand() {
            hhObj = new HelpHandler();
        }
        //命令执行方法,将调用请求接收者的业务方法
        public void execute() {
            hhObj.display();
        }
    }

    接收者

    帮助文档处理类

    public class HelpHandler {
    
        public void display() {
            System.out.println("显示帮助文档!");
        }
    
    
    }

     窗口处理类

    public class WindowHanlder {
    
        public void minimize() {
            System.out.println("将窗口最小化至托盘!");
        }
    
    }

    请求发送者

    public class FunctionButton {
        private String name; //功能键名称
        private Command command; //维持一个抽象命令对象的引用
        public FunctionButton(String name) {
            this.name = name;
        }
        public String getName() {
            return this.name;
        }
        //为功能键注入命令
        public void setCommand(Command command) {
            this.command = command;
        }
        //发送请求的方法
        public void onClick() {
            System.out.print("点击功能键:");
            command.execute();
        }
    }

    功能键设置窗口类

    public class FBSettingWindow {
        private String title; //窗口标题
        //定义一个ArrayList来存储所有功能键
        private ArrayList<FunctionButton> functionButtons = new ArrayList<FunctionButton>();
        public FBSettingWindow(String title) {
            this.title = title;
        }
        public void setTitle(String title) {
            this.title = title;
        }
    
        public String getTitle() {
            return this.title;
        }
        public void addFunctionButton(FunctionButton fb) {
            functionButtons.add(fb);
        }
        public void removeFunctionButton(FunctionButton fb) {
            functionButtons.remove(fb);
        }
        //显示窗口及功能键
        public void display() {
            System.out.println("显示窗口:" + this.title);
            System.out.println("显示功能键:");
            for (Object obj : functionButtons) {
                System.out.println(((FunctionButton)obj).getName());
            }
            System.out.println("------------------------------");
        }
    
    }
    public class client {
    
        public static void main(String[] args) {
    
            FBSettingWindow fbsw = new FBSettingWindow("功能键设置");
            FunctionButton fb1,fb2;
            fb1 = new FunctionButton("功能键1");
            fb2 = new FunctionButton("功能键1");
            Command command1,command2;
        //通过读取配置文件和反射生成具体命令对象
            command1 = new HelpCommand();
    
            command2 = new MinimizeCommand();
        //将命令对象注入功能键
            fb1.setCommand(command1);
            fb2.setCommand(command2);
            fbsw.addFunctionButton(fb1);
            fbsw.addFunctionButton(fb2);
            fbsw.display();
        //调用功能键的业务方法
            fb1.onClick();
            fb2.onClick();
        }
    
    }

     图构:

     

    优点

    (1) 降低系统的耦合度。由于请求者与接收者之间不存在直接引用,因此请求者与接收者之间
    实现完全解耦,相同的请求者可以对应不同的接收者,同样,相同的接收者也可以供不同的
    请求者使用,两者之间具有良好的独立性。


    (2) 新的命令可以很容易地加入到系统中。由于增加新的具体命令类不会影响到其他类,因此
    增加新的具体命令类很容易,无须修改原有系统源代码,甚至客户类代码,满足“开闭原则”的
    要求。


    (3) 可以比较容易地设计一个命令队列或宏命令(组合命令)。


    (4) 为请求的撤销(Undo)和恢复(Redo)操作提供了一种设计和实现方案。

     缺点

    使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个对请求接收者的调
    用操作都需要设计一个具体命令类,因此在某些系统中可能需要提供大量的具体命令类,这
    将影响命令模式的使用。

     适用场景

    (1) 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。请求调用者
    无须知道接收者的存在,也无须知道接收者是谁,接收者也无须关心何时被调用。


    (2) 系统需要在不同的时间指定请求、将请求排队和执行请求。一个命令对象和请求的初始调
    用者可以有不同的生命期,换言之,最初的请求发出者可能已经不在了,而命令对象本身仍
    然是活动的,可以通过该命令对象去调用请求接收者,而无须关心请求调用者的存在性,可
    以通过请求日志文件等机制来具体实现。


    (3) 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。


    (4) 系统需要将一组操作组合在一起形成宏命令。

  • 相关阅读:
    Effective C++第三遍
    SQL基础教程
    hibernate 数据关联多对多
    hibernate 数据关联一对一
    hibernate 数据关联一对多
    hibernate Criteria查询
    hibernate HQL查询
    hibernate 持久化对象的生命周期
    hibernate的配置
    微博登录
  • 原文地址:https://www.cnblogs.com/Mrchengs/p/10899245.html
Copyright © 2011-2022 走看看