第17章 命令模式

17.1 命令模式概述

image

命令模式(Command Pattern):将一个请求封装为一个对象,从而可用不同的对象对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。

  • 对象行为型模式
  • 动作(Action)模式
  • 事务(Transaction)模式

17.2 命令模式结构与实现

17.2.1 命令模式结构

image

  1. Command(抽象命令类):抽象命令类―般是一个抽象类或接口,在其中声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作。
  2. ConcreteCommand(具体命令类):具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法,它对应具体的接收者对象,将接收者对象的动作绑定其中。具体命令类在实现execute()方法时将调用接收者对象的相关操作(Action)。
  3. Invoker(调用者):调用者即请求发送者,它通过命令对象来执行请求。一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联关系。在程序运行时可以将一个具体命令对象注入其中,再调用具体命令对象的execute()方法,从而实现间接调用请求接收者的相关操作。
  4. Receiver(接收者):接收者执行与请求相关的操作,具体实现对请求的业务处理。

17.2.2 命令模式实现

Command(抽象命令类):

package designpatterns.command;

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

Invoker(调用者):

public class Invoker {
    private Command command;

    //构造注入
    public Invoker(Command command) {
        this.command = command;
    }

    //设值注入
    public void setCommand(Command command) {
        this.command = command;
    }

    //业务方法,用于调用命令类的execute()方法
    public void call() {
        command.execute();
    }
}

ConcreteCommand(具体命令类):

public class ConcreteCommand extends Command {
    private Receiver receiver;//维持一个对请求接收者对象的引用

    public void execute() {
        receiver.action();//调用请求接收者的业务处理方法action( )
    }
}

Receiver(接收者):

public class Receiver {
    public void action() {
        //具体操作
    }
}

17.3 命令模式应用实例

实例说明

       为了用户使用方便,某系统提供了一系列功能键,用户可以自定义功能键的功能,例如功能键FunctionButton可以用于退出系统(由SystemExitClass类来实现),也可以用于显示帮助文档(由DisplayHelpClass类来实现)。
       用户可以通过修改配置文件改变功能键的用途,现使用命令模式设计该系统,使得功能键类与功能类之间解耦,可为同一个功能键设置不同的功能。

实例类图

image

  • 调用者
    • FunctionButton
  • 请求接收者
    • SystemExitClass
    • DisplayHelpClass
  • 抽象命令类
    • Command
  • 具体命令类
    • ExitCommand
    • HelpCommand
FunctionButton:功能键类,充当请求调用者(请求发送者)。
package designpatterns.command;

public class FunctionButton {
    private Command command;//维持一个抽象命令对象的引用

    //为功能键注入命令
    public void setCommand(Command command) {
        this.command = command;
    }

    //发送请求的方法
    public void click() {
        System.out.print("单击功能键:");
        command.execute();
    }
}
Command:抽象命令类。
package designpatterns.command;

public abstract class Command {
    public abstract void execute();
}
ExitCommand:退出命令类,充当具体命令类。
package designpatterns.command;

public class ExitCommand extends Command {
    private SystemExitClass seObj;//维持对请求接收者的引用

    public ExitCommand() {
        seObj = new SystemExitClass();
    }

    //命令执行方法,将调用请求接收者的业务方法
    @Override
    public void execute() {
        seObj.exit();
    }
}
HelpCommand:帮助命令类,充当具体命令类。
package designpatterns.command;

public class HelpCommand extends Command {
    private DispalyHelpClass hcObj;//维持对请求接收者的引用

    public HelpCommand() {
        hcObj = new DispalyHelpClass();
    }

    //命令执行方法,将调用请求接收者的业务方法
    @Override
    public void execute() {
        hcObj.display();
    }
}
SystemExitClass:退出系统模拟实现类,充当请求接收者。
package designpatterns.command;

public class SystemExitClass {
    public void exit() {
        System.out.println("退出系统! ");
    }
}
DisplayHelpClass:显示帮助文档模拟实现类,充当请求接收者。
package designpatterns.command;

public class DispalyHelpClass {
    public void display(){
        System.out.println("显示帮助文档!");
    }
}
配置文件config.xml,在配置文件中存储了具体命令类的类名。
<?xml version="1.0"?>
<config>
    <className>designpatterns.command.ExitCommand</className>
</config>
XMLUtil:工具类。
package designpatterns.command;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;

public class XMLUtil {
    //该方法用于从XML配置文件中提取具体类的类名,并返回一个实例对象
    public static Object getBean() {
        try {
            //创建DOM文档对象
            DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = dFactory.newDocumentBuilder();
            Document doc;
            doc = builder.parse(new File("src//designpatterns//command//config.xml"));

            //获取包含类名的文本结点
            NodeList nl = doc.getElementsByTagName("className");
            Node classNode = nl.item(0).getFirstChild();
            String cName = classNode.getNodeValue();

            //通过类名生成实例对象并将其返回
            Class c = Class.forName(cName);
            Object obj = c.newInstance();
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
Client:客户端测试类。
package designpatterns.command;

public class Client {
    public static void main(String[] args) {
        FunctionButton fb = new FunctionButton();
        Command command;
        command = (Command) XMLUtil.getBean();
        fb.setCommand(command);
        fb.click();
    }
}

结果及分析

image

posted @ 2022-04-20 14:48  手持六脉神剑的外星人  阅读(150)  评论(0编辑  收藏  举报