大家好,这里是每周都陪你进步的网管,假期归来咱们继续更新设计模式系列,这次要和大家一起学习的是命令模式,如果你对领域驱动设计感兴趣,这个模式一定要好好学,命令模式是DDD风格的框架中高频使用的一个模式。
创新互联是一家专注于成都做网站、网站建设与策划设计,三山网站建设哪家好?创新互联做网站,专注于网站建设十余年,网设计领域的专业建站公司;建站业务涵盖:三山等地区。三山做网站价格咨询:18980820575
命令模式是一种行为型模式。它通过将请求封装为一个独立的对象即命令对象,来解耦命令的调用者和接收者,使得调用者和接收者不直接交互。在命令对象里会包含请求相关的全部信息,每一个命令都是一个操作的请求: 请求方发出请求要求执行一个操作; 接收方收到请求,并执行操作。
命令模式中有如下必须存在的基础组件:
直接这么描述听起来比较抽象,下面我们结合UML类图详细看一下命令模式内部这几种基础组件的特性和具有的行为。
命令模式的构成如下图所示
请求的接收者Receiver我们做了简化,根据实际场景复杂度的需要我们也可以进一步抽象出接口和实现类,图中表示的命令模式一共由五种角色构成,下面详细解释下它们各自的特性和具有的行为
发送者是通常我们能接触到的终端,比如电视的遥控器,点击音量按钮发送加音量的命令,电视机里的芯片就是接收者负责完成音量添加的处理逻辑。
下面我们通过一个让PS5完成各种操作的例子,结合Golang代码实现理解一下用代码怎么实现命令模式。
假设PS5的CPU支持A、B、C三个命令操作,
"本文使用的完整可运行源码
去公众号「网管叨bi叨」发送【设计模式】即可领取"
type CPU struct{}
func (CPU) ADoSomething() {
fmt.Println("a do something")
}
func (CPU) BDoSomething() {
fmt.Println("b do something")
}
type PS5 struct {
cpu CPU
}
func (p PS5) ACommand() {
p.cpu.ADoSomething()
}
func (p PS5) BCommand() {
p.cpu.ADoSomething()
}
func main() {
cpu := CPU{}
ps5 := PS5{cpu}
ps5.ACommand()
ps5.BCommand()
}
后续还可能会给CPU增加其他命令操作,以及需要支持命令宏(即命令组合操作)。如果每次都修改PS5的类定义,显然不符合面向对象开闭原则(Open close principle)的设计理念。
通过命令模式,我们把PS5抽象成命令发送者、CPU对象作为执行业务逻辑的命令接收者,然后引入引入Command 接口把两者做解耦,来满足开闭原则。
下面看一下用命令模式解耦后的代码实现,模式中各个角色的职责、实现思路等都在代码注释里做了标注,咱们直接看代码吧。
"本文使用的完整可运行源码
去公众号「网管叨bi叨」发送【设计模式】即可领取"
// 命令接收者,负责逻辑的执行
type CPU struct{}
func (CPU) ADoSomething(param int) {
fmt.Printf("a do something with param %v\n", param)
}
func (CPU) BDoSomething(param1 string, param2 int) {
fmt.Printf("b do something with params %v and %v \n", param1, param2)
}
func (CPU) CDoSomething() {
fmt.Println("c do something with no params")
}
// 接口中仅声明一个执行命令的方法 Execute()
type Command interface {
Execute()
}
// 命令对象持有一个指向接收者的引用,以及请求中的所有参数,
type ACommand struct {
cpu *CPU
param int
}
// 命令不会进行逻辑处理,调用Execute方法会将发送者的请求委派给接收者对象。
func (a ACommand) Execute() {
a.cpu.ADoSomething(a.param)
a.cpu.CDoSomething()// 可以执行多个接收者的操作完成命令宏
}
func NewACommand(cpu *CPU, param int) Command {
return ACommand{cpu, param}
}
"本文使用的完整可运行源码
去公众号「网管叨bi叨」发送【设计模式】即可领取"
type BCommand struct {
state bool // Command 里可以添加些状态用作逻辑判断
cpu *CPU
param1 string
param2 int
}
func (b BCommand) Execute() {
if b.state {
return
}
b.cpu.BDoSomething(b.param1, b.param2)
b.state = true
b.cpu.CDoSomething()
}
func NewBCommand(cpu *CPU, param1 string, param2 int) Command {
return BCommand{false,cpu, param1, param2}
}
type PS5 struct {
commands map[string]Command
}
// SetCommand方法来将 Command 指令设定给PS5。
func (p *PS5) SetCommand(name string, command Command) {
p.commands[name] = command
}
// DoCommand方法选择要执行的命令
func (p *PS5) DoCommand(name string) {
p.commands[name].Execute()
}
func main() {
cpu := CPU{}
// main方法充当客户端,创建并配置具体命令对象, 完成命令与执行操作的接收者的关联。
ps5 := PS5{make(map[string]Command)}
ps5.SetCommand("a", NewACommand(&cpu, 1))
ps5.SetCommand("b", NewBCommand(&cpu, "hello", 2))
ps5.DoCommand("a")
ps5.DoCommand("b")
}
本文的完整源码,已经同步收录到我整理的电子教程里啦,可向我的公众号「网管叨bi叨」发送关键字【设计模式】领取。
公众号「网管叨bi叨」发送关键字【设计模式】领取。
关于命令模式的学习和实践应用,推荐有Java背景的同学看一下阿里开源的框架COLA 3.0,里面融合了不少DDD的概念,其中的Application层主要就是各种Command、Query对象封装了客户端的请求,它们的Execute方法负责将请求转发给Domain层进行处理从而完成业务逻辑。
最后我们再来总结一下命令模式的优缺点。
命令模式的优点
命令模式的缺点
文章名称:Go设计模式--命令模式
文章位置:http://www.shufengxianlan.com/qtweb/news31/177981.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联