golang设计模式之访问者模式
访问者模式可以给一系列对象透明的添加功能,并且把相关代码封装到一个类中。
对象只要预留访问者接口Accept则后期为对象添加功能的时候就不需要改动对象。
大概的流程就是:
从结构容器中取出元素
创建一个访问者
将访问者载入传入的元素(即让访问者访问元素)
获取输出
例如,一个对象的方法,在测试环境要打印出: 这是测试环境,在生产环境中要打印出: 这是生产环境
一般最开始会这样写:
type EnvExample struct { } func (e EnvExample) Print() { if GetEnv() == "testing" { fmt.Println("这是测试环境") } if GetEnv() == "production" { fmt.Println("这是生产环境") } }
这样这个Print() 方法的逻辑就耦合在当前结构体中了,扩展性差,现在假如我们要添加一个打印 这是本地环境 的逻辑呢?
我们就需要更改Print() 方法了,注意! 这是一个非常简单的例子,可以随意更改Print() 方法,没什么关系,但是在实际开发过程中
一个函数的实现是十分复杂的,有可能更改了这个方法,会导致整个系统崩溃,所以解耦是一个十分迫切的需要.
对象容器也只是一个容器而已,我就不实现了,用Map,List都能实现
1. 定义访问者接口
// 定义访问者接口 type IVisitor interface { Visit() // 访问者的访问方法 }
2. 实现该接口
type ProductionVisitor struct { } func (v ProductionVisitor) Visit() { fmt.Println("这是生产环境") } type TestingVisitor struct { } func (t TestingVisitor) Visit() { fmt.Println("这是测试环境") }
3. 创建元素接口
// 定义元素接口 type IElement interface { Accept(visitor IVisitor) }
4. 实现元素接口
type Element struct { } func (el Element) Accept(visitor IVisitor) { visitor.Visit() }
5. 修改 Print() 方法
type EnvExample struct { Element } func (e EnvExample) Print(visitor IVisitor) { e.Element.Accept(visitor) }
6. 开始调用
// 创建一个元素 e := new(Element) e.Accept(new(ProductionVisitor)) // output: 这是生产环境 e.Accept(new(TestingVisitor)) // output: 这是测试环境 m := new(EnvExample) m.Print(new(ProductionVisitor)) m.Print(new(TestingVisitor))