乐趣区

关于编辑器:计模式之结构型模式

简述
在面向对象编程中,有两个常见的对象设计办法,组合和继承,两者都能够解决代码复用的问题,然而应用后者时容易呈现继承档次过深,对象关系过于简单的副作用,从而导致代码的可维护性变差。因而,一个经典的面向对象设计准则是:组合优于继承。

咱们都晓得,组合所示意的语义为“has-a”,也就是局部和整体的关系,最经典的组合模式形容如下:

将对象组合成树形构造以示意“局部 - 整体”的层次结构,使得用户对单个对象和组合对象的应用具备一致性。

Go 语言人造就反对了组合模式,而且从它不反对继承关系的特点来看,Go 也奉行了组合优于继承的准则,激励大家在进行程序设计时多采纳组合的办法。Go 实现组合模式的形式有两种,别离是间接组合(Direct Composition)和嵌入组合(Embedding Composition),上面咱们一起探讨这两种不同的实现办法。

Go 实现
间接组合(Direct Composition)的实现形式相似于 Java/C++,就是将一个对象作为另一个对象的成员属性。

一个典型的实现如《应用 Go 实现 GoF 的 23 种设计模式(一)》中所举的例子,一个 Message 构造体,由 Header 和 Body 所组成。那么 Message 就是一个整体,而 Header 和 Body 则为音讯的组成部分。

type Message struct {

Header *Header
Body   *Body

}
当初,咱们来看一个略微简单一点的例子,同样思考上一篇文章中所形容的插件架构格调的音讯解决零碎。后面咱们用形象工厂模式解决了插件加载的问题,通常,每个插件都会有一个生命周期,常见的就是启动状态和进行状态,当初咱们应用组合模式来解决插件的启动和进行问题。

首先给 Plugin 接口增加几个生命周期相干的办法:

复制代码
package plugin

// 插件运行状态
type Status uint8

const (

Stopped Status = iota
Started

)

type Plugin interface {
// 启动插件

Start()

// 进行插件

Stop()

// 返回插件以后的运行状态

Status() Status

}
// Input、Filter、Output 三类插件接口的定义跟上一篇文章相似
// 这里应用 Message 构造体代替了原来的 string,使得语义更清晰
type Input interface {

Plugin
Receive() *msg.Message

}

type Filter interface {

Plugin
Process(msg *msg.Message) *msg.Message

}

type Output interface {

Plugin
Send(msg *msg.Message)

}
复制代码
对于插件化的音讯解决零碎而言,所有皆是插件,因而咱们将 Pipeine 也设计成一个插件,实现 Plugin 接口:

复制代码
package pipeline

// 一个 Pipeline 由 input、filter、output 三个 Plugin 组成
type Pipeline struct {

status plugin.Status
input  plugin.Input
filter plugin.Filter
output plugin.Output

}

func (p *Pipeline) Exec() {

msg := p.input.Receive()
msg = p.filter.Process(msg)
p.output.Send(msg)

}
// 启动的程序 output -> filter -> input
func (p *Pipeline) Start() {

p.output.Start()
p.filter.Start()
p.input.Start()
p.status = plugin.Started
fmt.Println("Hello input plugin started.")

}
// 进行的程序 input -> filter -> output
func (p *Pipeline) Stop() {

p.input.Stop()
p.filter.Stop()
p.output.Stop()
p.status = plugin.Stopped
fmt.Println("Hello input plugin stopped.")

}

func (p *Pipeline) Status() plugin.Status {

return p.status

}
复制代码
一个 Pipeline 由 Input、Filter、Output 三类插件组成,造成了“局部 - 整体”的关系,而且它们都实现了 Plugin 接口,这就是一个典型的组合模式的实现。Client 无需显式地启动和进行 Input、Filter 和 Output 插件,在调用 Pipeline 对象的 Start 和 Stop 办法时,Pipeline 就曾经帮你按程序实现对应插件的启动和进行。

相比于上一篇文章,在本文中实现 Input、Filter、Output 三类插件时,须要多实现 3 个生命周期的办法。还是以上一篇文章中的 HelloInput、UpperFilter 和 ConsoleOutput 作为例子,具体实现如下:

复制代码
package plugin

type HelloInput struct {

status Status

}

func (h HelloInput) Receive() msg.Message {
// 如果插件未启动,则返回 nil

if h.status != Started {fmt.Println("Hello input plugin is not running, input nothing.")
    return nil
}
return msg.Builder().
    WithHeaderItem("content", "text").
    WithBodyItem("Hello World").
    Build()

}

func (h *HelloInput) Start() {

h.status = Started
fmt.Println("Hello input plugin started.")

}

func (h *HelloInput) Stop() {

h.status = Stopped
fmt.Println("Hello input plugin stopped.")

}

func (h *HelloInput) Status() Status {

return h.status

}
package plugin

type UpperFilter struct {

status Status

}

func (u UpperFilter) Process(msg msg.Message) *msg.Message {

if u.status != Started {fmt.Println("Upper filter plugin is not running, filter nothing.")
    return msg
}
for i, val := range msg.Body.Items {msg.Body.Items[i] = strings.ToUpper(val)
}
return msg

}

func (u *UpperFilter) Start() {

u.status = Started
fmt.Println("Upper filter plugin started.")

}

func (u *UpperFilter) Stop() {

u.status = Stopped
fmt.Println("Upper filter plugin stopped.")

}

func (u *UpperFilter) Status() Status {

return u.status

}

package plugin

type ConsoleOutput struct {

status Status

}

func (c ConsoleOutput) Send(msg msg.Message) {

if c.status != Started {fmt.Println("Console output is not running, output nothing.")
    return
}
fmt.Printf("Output:\n\tHeader:%+v, Body:%+v\n", msg.Header.Items, msg.Body.Items)

}

func (c *ConsoleOutput) Start() {

c.status = Started
fmt.Println("Console output plugin started.")

}

func (c *ConsoleOutput) Stop() {

c.status = Stopped
fmt.Println("Console output plugin stopped.")

}

func (c *ConsoleOutput) Status() Status {

return c.status

}
复制代码
测试代码如下:

复制代码
package test

func TestPipeline(t *testing.T) {

p := pipeline.Of(pipeline.DefaultConfig())
p.Start()
p.Exec()
p.Stop()

}
// 运行后果
=== RUN TestPipeline
Console output plugin started.
Upper filter plugin started.
Hello input plugin started.
Pipeline started.
Output:

Header:map[content:text], Body:[HELLO WORLD]

Hello input plugin stopped.
Upper filter plugin stopped.
Console output plugin stopped.
Hello input plugin stopped.
— PASS: TestPipeline (0.00s)
PASS
复制代码
组合模式的另一种实现,嵌入组合(Embedding Composition),其实就是利用了 Go 语言的匿名成员个性,实质上跟间接组合是统一的。

还是以 Message 构造体为例,如果采纳嵌入组合,则看起来像是这样:

type Message struct {

Header
Body

}
// 应用时,Message 能够援用 Header 和 Body 的成员属性,例如:
msg := &Message{}
msg.SrcAddr = “192.168.0.1”

退出移动版