Go和Java实现命令模式

Go和Java实现命令模式

下面通过一个烧烤的例子来说明命令模式的使用。

1、命令模式

命令模式是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调

用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

  • 意图:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化,对请求排队或记录请求日

    志,以及支持可撤消的操作。

  • 主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为

    进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。

  • 何时使用:在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是

    不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者

    之间的松耦合。

  • 如何解决:通过调用者调用接受者执行命令,顺序:调用者→命令→接受者。

  • 关键代码:定义三个角色:1、received 真正的命令执行对象 2、Command 3、invoker 使用命令对象的入口

  • 应用实例:struts 1 中的 action 核心控制器 ActionServlet 只有一个,相当于 Invoker,而模型层的类会随着

    不同的应用有不同的模型类,相当于具体的 Command。

  • 优点:1、降低了系统耦合度。 2、新的命令可以很容易添加到系统中去。

  • 缺点:使用命令模式可能会导致某些系统有过多的具体命令类。

  • 使用场景:认为是命令的地方都可以使用命令模式,比如: 1、GUI 中每一个按钮都是一条命令。 2、模拟

    CMD。

  • 注意事项:系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作,也可以考虑使用命令模式。

  • 适用性:

    抽象出待执行的动作以参数化某对象。

    在不同的时刻指定、排列和执行请求。

    支持取消操作。

    支持修改日志,这样当系统崩溃时,这样修改可以被重做一遍。

    用构建在原语操作上的高层操作构造一个系统。

2、Go实现命令模式

go 复制代码
package command

// ========== 声明执行操作的接口 ==========
// ========== Command ==========
type Command interface {
	// 执行命令
	executeCommand()
}
go 复制代码
package command

// ========== 将一个接收者对象绑定于一个动作,调用接收者相应的操作,以实现Execute ==========
// ========== BakeChickWingCommand烤鸡翅命令 ==========
type BakeChickWingCommand struct {
	Barbecuer
}

func (bakeChickWingCommand *BakeChickWingCommand) executeCommand() {
	bakeChickWingCommand.Barbecuer.bakeChickWing()
}
go 复制代码
package command

// ========== 将一个接收者对象绑定于一个动作,调用接收者相应的操作,以实现Execute ==========
// ========== BakeMuttonCommand烤羊肉串命令 ==========
type BakeMuttonCommand struct {
	Barbecuer
}

func (bakeMuttonCommand *BakeMuttonCommand) executeCommand() {
	bakeMuttonCommand.Barbecuer.bakeMutton()
}
go 复制代码
package command

import "fmt"

// 知道如何实现与执行一个请求相关的操作,任何类都可能作为一个接收者
// ========== Barbecuer烧烤串者 ==========
type Barbecuer struct{}

// 考羊肉串
func (barbecuer *Barbecuer) bakeMutton() {
	fmt.Println("考羊肉串!")
}

// 考鸡翅
func (barbecuer *Barbecuer) bakeChickWing() {
	fmt.Println("考鸡翅!")
}
go 复制代码
package command

// 要求该命令执行这个请求
// ========== 服务员Waiter ==========
type Waiter struct {
	Command
}

func (waiter *Waiter) SetOrder(command Command) {
	waiter.Command = command
}

// 通知执行
func (waiter *Waiter) Execute() {
	waiter.Command.executeCommand()
}
go 复制代码
package main

import . "proj/command"

func main() {
	// 开店前的准备
	// 烧烤师傅
	barbecuer := Barbecuer{}
	// 烧烤菜单
	bakeMuttonCommand := BakeMuttonCommand{Barbecuer: barbecuer}
	bakeChickWingCommand := BakeChickWingCommand{Barbecuer: barbecuer}
	// 服务员
	waiter := Waiter{}
	// 开门营业
	// 根据用户需要通知厨房
	waiter.SetOrder(&bakeMuttonCommand)
	// 开始制作
	waiter.Execute()
	waiter.SetOrder(&bakeChickWingCommand)
	waiter.Execute()
}
shell 复制代码
# 程序输出
考羊肉串!
考鸡翅!

3、Java实现命令模式

java 复制代码
package com.command;

// ========== 声明执行操作的接口 ==========
// ========== Command ==========
public abstract class Command {
    protected Barbecuer receive;

    public Command(Barbecuer receive) {
        this.receive = receive;
    }

    // 执行命令
    public abstract void executeCommand();
}
java 复制代码
package com.command;

// ========== 将一个接收者对象绑定于一个动作,调用接收者相应的操作,以实现Execute ==========
// ========== BakeChickWingCommand烤鸡翅命令 ==========
public class BakeChickWingCommand extends Command {
    
    public BakeChickWingCommand(Barbecuer receive) {
        super(receive);
    }

    @Override
    public void executeCommand() {
        this.receive.bakeChickWing();
    }
}
java 复制代码
package com.command;

// ========== 将一个接收者对象绑定于一个动作,调用接收者相应的操作,以实现Execute ==========
// ========== BakeMuttonCommand烤羊肉串命令 ==========
public class BakeMuttonCommand extends Command {

    public BakeMuttonCommand(Barbecuer receive) {
        super(receive);
    }

    @Override
    public void executeCommand() {
        this.receive.bakeMutton();
    }
}
java 复制代码
package com.command;

// 知道如何实现与执行一个请求相关的操作,任何类都可能作为一个接收者
// ========== Barbecuer烧烤串者 ==========
public class Barbecuer {

    // 考羊肉串
    public void bakeMutton(){
        System.out.println("考羊肉串!");
    }

    // 考鸡翅
    public void bakeChickWing(){
        System.out.println("考鸡翅!");
    }
}
java 复制代码
package com.command;

// 要求该命令执行这个请求
// ========== 服务员Waiter ==========
public class Waiter {
    private Command command;

    public void setOrder(Command command) {
        this.command = command;
    }

    // 通知执行
    public void execute() {
        this.command.executeCommand();
    }
}
java 复制代码
package com.command;

public class Test {
    public static void main(String[] args) {
        // 开店前的准备
        // 烧烤师傅
        Barbecuer barbecuer = new Barbecuer();
        // 烧烤菜单
        Command bakeMuttonCommand = new BakeMuttonCommand(barbecuer);
        Command bakeChickWingCommand = new BakeChickWingCommand(barbecuer);
        // 服务员
        Waiter waiter = new Waiter();
        // 开门营业
        // 根据用户需要通知厨房
        waiter.setOrder(bakeMuttonCommand);
        // 开始制作
        waiter.execute();
        waiter.setOrder(bakeChickWingCommand);
        waiter.execute();
    }
}
shell 复制代码
# 程序输出
考羊肉串!
考鸡翅!
相关推荐
缺点内向3 小时前
Java:创建、读取或更新 Excel 文档
java·excel
带刺的坐椅3 小时前
Solon v3.4.7, v3.5.6, v3.6.1 发布(国产优秀应用开发框架)
java·spring·solon
四谎真好看5 小时前
Java 黑马程序员学习笔记(进阶篇18)
java·笔记·学习·学习笔记
桦说编程5 小时前
深入解析CompletableFuture源码实现(2)———双源输入
java·后端·源码
java_t_t5 小时前
ZIP工具类
java·zip
lang201509285 小时前
Spring Boot优雅关闭全解析
java·spring boot·后端
小羊在睡觉6 小时前
golang定时器
开发语言·后端·golang
pengzhuofan6 小时前
第10章 Maven
java·maven
百锦再7 小时前
Vue Scoped样式混淆问题详解与解决方案
java·前端·javascript·数据库·vue.js·学习·.net
刘一说7 小时前
Spring Boot 启动慢?启动过程深度解析与优化策略
java·spring boot·后端