访问者模式(Visitor Design Pattern)

访问者模式是一种操作一组对象的操作,它的目的是不改变对象的定义,但可以新增不同的访问者来定义新的操作。访问者的核心思想是为了访问比较复杂的数据结构,不去改变原数据结构,而是把对数据的操作抽象出来,在访问的过程中以回调形式在访问者中处理逻辑操作。如果要新增一组操作,那么只需要增加一个新的访问者。

举个例子,假如一个对象的方法,我们要在生产环境和测试环境中打印处不同的内容,一般会这样写:

func(e Example) Print() {
    if env == "testing" {
        println("测试环境")
    } else if env == "production" {
        println("生产环境")
    }
}

这里的Print方法里的逻辑就耦合到结构体里了,如果又增加一个预发布环境,就需要再添加一个新的逻辑分支。这里的代码逻辑很简单,修改Print函数影响不是很大,但是在实际的开发过程中一个函数可能是非常复杂的,一旦改动了这个方法可能会出现问题,所以这种方式的扩展性很差,那就需要对这里的代码进行解耦了。

代码示例

package visitor

import "fmt"

//访问者接口
type IVisitor interface {
    Visite() //访问者的访问方法
}

//具体访问者
type ProductionVisitor struct {
    Env string
}

func (v ProductionVisitor) Visite() {
    if v.Env == "production" {
        fmt.Println("这是生成环境的输出")
    }
}

type TestingVisitor struct {
    Env string
}

func (v TestingVisitor) Visite() {
    if v.Env == "testing" {
        fmt.Println("这是测试环境的输出")
    }
}

//IElement抽象元素,在其中声明一个accept()操作,它以一个抽象访问者作为参数
type IElement interface {
    Accept(visitor IVisitor)
}

//具体元素,它实现了accept()操作,在accept()中调用访问者的访问方法以便完成对一个元素的操作
type Element struct {
    visitors []IVisitor
}

func (ele *Element) Accept(visitor IVisitor) {
    ele.visitors = append(ele.visitors, visitor)
}

//修改打印输出方法
type ExampleLog struct {
    Element
}

func (ex ExampleLog) Print() {
    for _, v := range ex.visitors {
        v.Visite()
    }
}

调用:

ele := Element{}
// env := "production"
env := "testing"
ele.Accept(&ProductionVisitor{Env: env})
ele.Accept(&TestingVisitor{Env: env})

example := &ExampleLog{Element: ele}
example.Print()

// Output:
// 这是测试环境的输出

以上的代码将判断的逻辑放到了不同的结构体函数中,如果以后需要再添加一个预发布环境的处理逻辑的话,只需要再增加一个结构体实现对应的接口就可以了,这样就实现了代码的解耦。

results matching ""

    No results matching ""