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 复制代码
# 程序输出
考羊肉串!
考鸡翅!
相关推荐
慕城南风19 分钟前
Go语言中的defer,panic,recover 与错误处理
golang·go
豪宇刘1 小时前
MyBatis的面试题以及详细解答二
java·servlet·tomcat
秋恬意1 小时前
Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别
java·数据库·mybatis
FF在路上2 小时前
Knife4j调试实体类传参扁平化模式修改:default-flat-param-object: true
java·开发语言
真的很上进2 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
众拾达人2 小时前
Android自动化测试实战 Java篇 主流工具 框架 脚本
android·java·开发语言
皓木.2 小时前
Mybatis-Plus
java·开发语言
不良人天码星2 小时前
lombok插件不生效
java·开发语言·intellij-idea
守护者1703 小时前
JAVA学习-练习试用Java实现“使用Arrays.toString方法将数组转换为字符串并打印出来”
java·学习
源码哥_博纳软云3 小时前
JAVA同城服务场馆门店预约系统支持H5小程序APP源码
java·开发语言·微信小程序·小程序·微信公众平台