设计模式之命令模式(下)

这篇具有很好参考价值的文章主要介绍了设计模式之命令模式(下)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

2)完整解决方案
1.结构图

设计模式之命令模式(下),设计模式,设计模式,命令模式

FBSettingWindow是“功能键设置”界面类,FunctionButton充当请求调用者,Command充当抽象命令类,MinimizeCommand和HelpCommand充当具体命令类,WindowHanlder和HelpHandler充当请求接收者。

2.代码实现
import lombok.Data;
import java.util.*;

//功能键设置窗口类
@Data
public class FBSettingWindow {
    //窗口标题
    private String title;
    //定义一个ArrayList来存储所有功能键
    private ArrayList<FunctionButton> functionButtons = new ArrayList<FunctionButton>();

    public FBSettingWindow(String title) {
        this.title = 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("------------------------------");
    }
}

import lombok.Data;

//功能键类:请求发送者
@Data
class FunctionButton {
    //功能键名称
    private String name;
    //维持一个抽象命令对象的引用
    private Command command;

    public FunctionButton(String name) {
        this.name = name;
    }

    //发送请求的方法
    public void onClick() {
        System.out.print("点击功能键:");
        command.execute();
    }
}

//抽象命令类
abstract class Command {
    public abstract void execute();
}

//帮助命令类:具体命令类
public class HelpCommand extends Command {
    //维持对请求接收者的引用
    private HelpHandler hhObj;

    public HelpCommand() {
        hhObj = new HelpHandler();
    }

    //命令执行方法,将调用请求接收者的业务方法
    public void execute() {
        hhObj.display();
    }
}

//最小化命令类:具体命令类
public class MinimizeCommand extends Command {
    //维持对请求接收者的引用
    private WindowHanlder whObj;
    public MinimizeCommand() {
        whObj = new WindowHanlder();
    }

    //命令执行方法,将调用请求接收者的业务方法
    public void execute() {
        whObj.minimize();
    }
}

//帮助文档处理类:请求接收者
public class HelpHandler {
    public void display() {
        System.out.println("显示帮助文档!");
    }
}

//窗口处理类:请求接收者
public class WindowHanlder {
    public void minimize() {
        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("功能键2");

        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();
    }
}

注意

每一个具体命令类对应一个请求的处理者(接收者),通过向请求发送者注入不同的具体命令对象可以使得相同的发送者对应不同的接收者,从而实现“将一个请求封装为一个对象,用不同的请求对客户进行参数化”。

3)命令队列的实现
1.概述

将多个请求排队,当一个请求发送者发送一个请求时,将不止一个请求接收者产生响应,这些请求接收者将逐个执行业务方法,完成对请求的处理。

2.方案

增加一个CommandQueue类,由该类负责存储多个命令对象,而不同的命令对象可以对应不同的请求接收者。

3.代码实现

命令队列类

import java.util.*;
 
public class CommandQueue {
  //定义一个ArrayList来存储命令队列
	private ArrayList<Command> commands = new ArrayList<Command>();
	
	public void addCommand(Command command) {
		commands.add(command);
	}
	
	public void removeCommand(Command command) {
		commands.remove(command);
	}
	
    //循环调用每一个命令对象的execute()方法
	public void execute() {
		for (Object command : commands) {
			((Command)command).execute();
		}
	}
}

请求发送者类Invoker将针对CommandQueue编程

public class Invoker {
  //维持一个CommandQueue对象的引用
	private CommandQueue commandQueue; 
	
  //构造注入
	public Invoker(CommandQueue commandQueue) {
		this. commandQueue = commandQueue;
	}
	
  //设值注入
	public void setCommandQueue(CommandQueue commandQueue) {
		this.commandQueue = commandQueue;
	}
	
	//调用CommandQueue类的execute()方法
	public void call() {
		commandQueue.execute();
	}
}

客户端类

import com.xu.model.command.demo02.Invoker;

public class Client02 {
    public static void main(String args[]) {
        CommandQueue commandQueue = new CommandQueue();

        Command command1,command2;
        command1 = new HelpCommand();
        command2 = new MinimizeCommand();
        commandQueue.addCommand(command1);
        commandQueue.addCommand(command2);

        Invoker invoker = new Invoker(commandQueue);
        invoker.call();
    }
}

命令队列可以对一组对象(命令)进行批量处理,当一个发送者发送请求后,将有一系列接收者对请求作出响应,如果请求接收者的接收次序没有严格的先后次序,还可以使用多线程技术来并发调用命令对象的execute()方法,从而提高程序的执行效率。

4)撤销操作的实现
1.方案

通过在命令类中增加一个逆向操作(Undo)来实现。

通过保存对象的历史状态来实现,可以使用备忘录模式(Memento Pattern)。

2.结构图

设计模式之命令模式(下),设计模式,设计模式,命令模式

CalculatorForm充当请求发送者,实现了数据求和功能的加法类Adder充当请求接收者,界面类可间接调用加法类中的add()方法实现加法运算,并且提供了可撤销加法运算的undo()方法。

3.代码实现
//抽象命令类
abstract class AbstractCommand {
    //声明命令执行方法execute()
    public abstract int execute(int value);

    //声明撤销方法undo()
    public abstract int undo();
}

//具体命令类
public class ConcreteCommand extends AbstractCommand {
    private Adder adder = new Adder();
    private int value;

    //实现抽象命令类中声明的execute()方法,调用加法类的加法操作
    public int execute(int value) {
        this.value=value;
        return adder.add(value);
    }

    //实现抽象命令类中声明的undo()方法,通过加一个相反数来实现加法的逆向操作
    public int undo() {
        return adder.add(-value);
    }
}

//计算器界面类:请求发送者
public class CalculatorForm {
    private AbstractCommand command;

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

    //调用命令对象的execute()方法执行运算
    public void compute(int value) {
        int i = command.execute(value);
        System.out.println("执行运算,运算结果为:" + i);
    }

    //调用命令对象的undo()方法执行撤销
    public void undo() {
        int i = command.undo();
        System.out.println("执行撤销,运算结果为:" + i);
    }
}

//加法类:请求接收者
public class Adder {
    //定义初始值为0
    private int num = 0;

    //加法操作,每次将传入的值与num作加法运算,再将结果返回
    public int add(int value) {
        num += value;
        return num;
    }
}

public class Client {
    public static void main(String[] args) {
        CalculatorForm form = new CalculatorForm();
        AbstractCommand command;
        command = new ConcreteCommand();
        form.setCommand(command); //向发送者注入命令对象

        form.compute(10);
        form.compute(5);
        form.compute(10);
        form.undo();
    }
}

注意:本实例中只能实现一步撤销操作,因为没有保存命令对象的历史状态,可以通过引入一个命令集合来存储每一次操作时命令的状态,从而实现多次撤销操作,除了Undo操作外,还可以采用类似的方式实现恢复(Redo)操作,即恢复所撤销的操作。

5)请求日志
1.概述

请求日志是将请求的历史记录保存下来,通常以日志文件(Log File)的形式存储在磁盘中。

2.适用场景
  • 一旦系统发生故障,日志文件可以为系统提供一种恢复机制,在请求日志文件中可以记录用户对系统的每一步操作,从而让系统能够顺利恢复到某一个特定的状态。
  • 请求日志也可以用于实现批处理,在一个请求日志文件中可以存储一系列命令对象,例如一个命令队列。
  • 可以将命令队列中的所有命令对象都存储在一个日志文件中,每执行一个命令则从日志文件中删除一个对应的命令对象,防止因为断电或者系统重启等原因造成请求丢失,而且可以避免重新发送全部请求时造成某些命令的重复执行,只需读取请求日志文件,再继续执行文件中剩余的命令即可。
3.结构图

设计模式之命令模式(下),设计模式,设计模式,命令模式

4.代码实现
import lombok.Data;
import java.io.*;

//抽象命令类,由于需要将命令对象写入文件,因此它实现了Serializable接口
@Data
abstract class Command implements Serializable {
    //命令名称
    protected String name;
    //命令参数
    protected String args;
    //维持对接收者对象的引用
    protected ConfigOperator configOperator;

    public Command(String name) {
        this.name = name;
    }

    public void setConfigOperator(ConfigOperator configOperator) {
        this.configOperator = configOperator;
    }

    //声明两个抽象的执行方法execute()
    public abstract void execute(String args);

    public abstract void execute();
}

//增加命令类:具体命令
public class InsertCommand extends Command {
    public InsertCommand(String name) {
        super(name);
    }

    public void execute(String args) {
        this.args = args;
        configOperator.insert(args);
    }

    public void execute() {
        configOperator.insert(this.args);
    }
}

//修改命令类:具体命令
public class ModifyCommand extends Command {
    public ModifyCommand(String name) {
        super(name);
    }

    public void execute(String args) {
        this.args = args;
        configOperator.modify(args);
    }

    public void execute() {
        configOperator.modify(this.args);
    }
}

import lombok.Setter;
import java.util.ArrayList;

//配置文件设置窗口类:请求发送者
@Setter
public class ConfigSettingWindow {
    //定义一个集合来存储每一次操作时的命令对象
    private ArrayList<Command> commands = new ArrayList<Command>();
    private Command command;

    //执行配置文件修改命令,同时将命令对象添加到命令集合中
    public void call(String args) {
        command.execute(args);
        commands.add(command);
    }

    //记录请求日志,生成日志文件,将命令集合写入日志文件
    public void save() {
        FileUtil.writeCommands(commands);
    }

    //从日志文件中提取命令集合,并循环调用每一个命令对象的execute()方法来实现配置文件的重新设置
    public void recover() {
        ArrayList list;
        list = FileUtil.readCommands();

        for (Object obj : list) {
            ((Command) obj).execute();
        }
    }
}

import java.io.Serializable;

//配置文件操作类:请求接收者。
//由于ConfigOperator类的对象是Command的成员对象,它也将随Command对象一起写入文件,因此ConfigOperator也需要实现Serializable接口
class ConfigOperator implements Serializable {
    public void insert(String args) {
        System.out.println("增加新节点:" + args);
    }

    public void modify(String args) {
        System.out.println("修改节点:" + args);
    }

    public void delete(String args) {
        System.out.println("删除节点:" + args);
    }
}

import java.io.*;
import java.util.ArrayList;

//工具类:文件操作类
public class FileUtil {
    //将命令集合写入日志文件
    public static void writeCommands(ArrayList commands) {
        try {
            FileOutputStream file = new FileOutputStream("/Users/hhx/Desktop/config.log");
            //创建对象输出流用于将对象写入到文件中
            ObjectOutputStream objout = new ObjectOutputStream(new BufferedOutputStream(file));
            //将对象写入文件
            objout.writeObject(commands);
            objout.close();
        } catch (Exception e) {
            System.out.println("命令保存失败!");
            e.printStackTrace();
        }
    }

    //从日志文件中提取命令集合
    public static ArrayList readCommands() {
        try {
            FileInputStream file = new FileInputStream("/Users/hhx/Desktop/config.log");
            //创建对象输入流用于从文件中读取对象
            ObjectInputStream objin = new ObjectInputStream(new BufferedInputStream(file));

            //将文件中的对象读出并转换为ArrayList类型
            ArrayList commands = (ArrayList) objin.readObject();
            objin.close();
            return commands;
        } catch (Exception e) {
            System.out.println("命令读取失败!");
            e.printStackTrace();
            return null;
        }
    }
}

public class Client {
    public static void main(String[] args) {
        //定义请求发送者
        ConfigSettingWindow csw = new ConfigSettingWindow();
        //定义命令对象
        Command command;
        //定义请求接收者
        ConfigOperator co = new ConfigOperator();

        //四次对配置文件的更改
        command = new InsertCommand("增加");
        command.setConfigOperator(co);
        csw.setCommand(command);
        csw.call("网站首页");

        command = new InsertCommand("增加");
        command.setConfigOperator(co);
        csw.setCommand(command);
        csw.call("端口号");

        command = new ModifyCommand("修改");
        command.setConfigOperator(co);
        csw.setCommand(command);
        csw.call("网站首页");

        command = new ModifyCommand("修改");
        command.setConfigOperator(co);
        csw.setCommand(command);
        csw.call("端口号");

        System.out.println("----------------------------");
        System.out.println("保存配置");
        csw.save();

        System.out.println("----------------------------");
        System.out.println("恢复配置");
        System.out.println("----------------------------");
        csw.recover();
    }
}
6)宏命令
1.概述

宏命令(Macro Command)又称为组合命令,它是组合模式和命令模式联用的产物。

宏命令是一个具体命令类,它拥有一个集合属性,在该集合中包含了对其他命令对象的引用。

2.原理

通常宏命令不直接与请求接收者交互,而是通过它的成员来调用接收者的方法,当调用宏命令的execute()方法时,将递归调用它所包含的每个成员命令的execute()方法,一个宏命令的成员可以是简单命令,还可以继续是宏命令。

执行一个宏命令将触发多个具体命令的执行,从而实现对命令的批处理。

3.结构图

设计模式之命令模式(下),设计模式,设计模式,命令模式

7)总结
1.优点
  • 由于请求者与接收者之间不存在直接引用,因此请求者与接收者之间实现完全解耦。

  • 由于增加新的具体命令类不会影响到其他类,因此增加新的具体命令类很容易,无须修改原有系统源代码,甚至客户类代码。

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

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

2.缺点
  • 使用命令模式可能会导致系统有过多的具体命令类。
3.适用场景
  • 系统需要将请求调用者和请求接收者解耦。

  • 系统需要在不同的时间指定请求、将请求排队和执行请求,一个命令对象和请求的初始调用者可以有不同的生命期,可以通过该命令对象去调用请求接收者,可以通过请求日志文件等机制来实现。

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

  • 系统需要将一组操作组合在一起形成宏命令。文章来源地址https://www.toymoban.com/news/detail-846933.html

到了这里,关于设计模式之命令模式(下)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 设计模式(19)命令模式

    一、介绍: 1、定义:命令模式(Command Pattern)是一种行为设计模式,它将请求封装为一个对象,从而使你可以使用不同的请求对客户端进行参数化。命令模式还支持请求的排队、记录日志、撤销操作等功能。 2、组成结构: (1)命令接口(Command):定义执行命令的方法,可

    2024年02月07日
    浏览(37)
  • 【设计模式】命令模式

    【设计模式】命令模式——行为型模式 定义: 将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行存储、传递、调用、增加与管理。 命令模式包含以下主要角色: 抽象命令类(Command)角

    2024年02月03日
    浏览(35)
  • 设计模式—行为型模式之命令模式

    命令(Command)模式:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理。 命令模式包含以下主要角色。 抽象命令类(Command)角色:声明执行命令的接口,

    2024年01月25日
    浏览(40)
  • 设计模式之命令模式【行为型模式】

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您: 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持,想组团高效学习… 想写博

    2024年02月01日
    浏览(40)
  • 设计模式-命令模式(Command)

    命令模式(Command Pattern)是一种行为型设计模式,也被称为动作模式或事务模式。它的核心思想是将一个请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化。对请求排队或记录,以及支持可撤销的操作。命令模式的主要目的是将发出请求的对象和执行请求的

    2024年04月27日
    浏览(33)
  • 设计模式行为型——命令模式

    目录 命令模式的定义      命令模式的实现 命令模式角色 命令模式类图 命令模式举例 命令模式代码实现 命令模式的特点 优点 缺点 使用场景 注意事项         命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。是对命令的封装,每一个命令都是

    2024年02月14日
    浏览(42)
  • Java设计模式-命令模式

    命令模式,将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化。对请求排队或记录请求日志,以及支持可撤销的操作。 命令模式乍一看,有点懵懵的。即使这个定义看完,也是不明所以。但是结合例子来讲的话,就比较容易理解了。 其实它就是把一个

    2024年02月15日
    浏览(34)
  • 行为型设计模式——命令模式

    日常生活中,我们出去吃饭都会遇到下面的场景。 定义: 将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行存储、传递、调用、增加与管理。命令模式包含以下主要角色: 抽象命令类(

    2024年01月17日
    浏览(46)
  • 【软考】设计模式之命令模式

    1. 说明 1.命令模式(Command Pattern)是一种数据驱动的设计模式。 2.属于行为型模式。 3.请求以命令的形式被封装在对象中,并传递给调用对象。 4.调用对象寻找可以处理该命令的合适对象,并将该命令传递给相应的对象,由该对象执行命令。 5.将请求(行为)封装为对象,从

    2024年04月16日
    浏览(23)
  • 【软件设计模式之命令模式】

    命令模式是一种行为设计模式,它在软件开发中扮演着特殊的角色,尤其是在处理操作请求、排队请求、记录日志,以及支持可撤销操作方面。 命令模式将请求封装成对象,从而允许使用者与接收者解耦,使用不同的请求、队列或日志来参数化其他对象。它也支持可撤销操作

    2024年02月19日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包