• 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) 系统需要将一组操作组合在一起形成宏命令。

  • 相关阅读:
    Codeforces 787D. Legacy 线段树优化建图+最短路
    Codeforces 1051E. Vasya and Big Integers
    BZOJ3261 最大异或和
    BZOJ3531 SDOI2014 旅行
    洛谷P2468 SDOI 2010 粟粟的书架
    2018 ICPC 焦作网络赛 E.Jiu Yuan Wants to Eat
    HDU6280 From Tree to Graph
    HDU5985 Lucky Coins 概率dp
    (HDU)1334 -- Perfect Cubes (完美立方)
    (HDU)1330 -- Deck (覆盖物)
  • 原文地址:https://www.cnblogs.com/Mrchengs/p/10899245.html
Copyright © 2020-2023  润新知