From 0c69fdb72692a818e98721f0e6b21507bf4f86ff Mon Sep 17 00:00:00 2001 From: Edward Date: Mon, 4 May 2020 16:12:01 +0800 Subject: [PATCH] finish visitor pattern --- behavior/07_visitor/README.md | 12 +++- behavior/07_visitor/visitor.go | 105 ++++++++++++---------------- behavior/07_visitor/visitor_test.go | 29 +++++--- 3 files changed, 74 insertions(+), 72 deletions(-) diff --git a/behavior/07_visitor/README.md b/behavior/07_visitor/README.md index 6694a66..d1584d7 100644 --- a/behavior/07_visitor/README.md +++ b/behavior/07_visitor/README.md @@ -1,6 +1,14 @@ # 访问者模式 -访问者模式可以给一系列对象透明的添加功能,并且把相关代码封装到一个类中。 + 访问者模式, -对象只要预留访问者接口`Accept`则后期为对象添加功能的时候就不需要改动对象。 +访问者模式的目的是为了解耦对象和对象的使用和处理逻辑,一边提供资源,一边使用,也可以说是解耦生产出来的产品和产品消费者。 + +一个石油的例子,油田提供石油,不同的客户将石油用到不同的地方,可能用于生产武器,可能用于提纯材料,生产服装,也可能只是用于只是用于提供动力,这些客户就是石油的不同visitor. + +客户买石油的时候,都要遵循油田的购买方式,否则,就不卖给你,这个特定的购买方式就是指Visitor模式中常说的Accept方法。 + +打游戏是个不错的例子。 + +玩家角色需要跟NPC,其他玩家,以及游戏环境,交换这些都是Visit的过程. diff --git a/behavior/07_visitor/visitor.go b/behavior/07_visitor/visitor.go index 2c7a3c4..a80167e 100644 --- a/behavior/07_visitor/visitor.go +++ b/behavior/07_visitor/visitor.go @@ -2,73 +2,58 @@ package visitor import "fmt" -type Customer interface { - Accept(Visitor) +//////////////////////////////// +//使用石油的例子 + +//IGasResource 作为资源提供接口 +type IGasResource interface { + Accept(IGasVisitor) } -type Visitor interface { - Visit(Customer) +//gas 汽油 +type gas struct { + density int } -type EnterpriseCustomer struct { +//IGasVisitor 访问者接口 +type IGasVisitor interface { + Visit(gas) +} + +//Accept 接待汽油客户 +func (g gas) Accept(visitor IGasVisitor) { + visitor.Visit(g) +} + +//diesel 柴油 +type diesel struct { + energy int +} + +//IDieselVisitor 访问者接口 +type IDieselVisitor interface { + Visit(diesel) +} + +//Accept 提供柴油 +func (d diesel) Accept(visitor IDieselVisitor) { + visitor.Visit(d) +} + +//militaryFactory 军工厂,消费石油,制造务器 +type militaryFactory struct { name string } -type CustomerCol struct { - customers []Customer +//Visit 军工厂只够买柴油,制造武器 +func (m *militaryFactory) Visit(d diesel) { + fmt.Println("militaryFactory: use diesel with inner energy", d.energy) } -func (c *CustomerCol) Add(customer Customer) { - c.customers = append(c.customers, customer) -} - -func (c *CustomerCol) Accept(visitor Visitor) { - for _, customer := range c.customers { - customer.Accept(visitor) - } -} - -func NewEnterpriseCustomer(name string) *EnterpriseCustomer { - return &EnterpriseCustomer{ - name: name, - } -} - -func (c *EnterpriseCustomer) Accept(visitor Visitor) { - visitor.Visit(c) -} - -type IndividualCustomer struct { - name string -} - -func NewIndividualCustomer(name string) *IndividualCustomer { - return &IndividualCustomer{ - name: name, - } -} - -func (c *IndividualCustomer) Accept(visitor Visitor) { - visitor.Visit(c) -} - -type ServiceRequestVisitor struct{} - -func (*ServiceRequestVisitor) Visit(customer Customer) { - switch c := customer.(type) { - case *EnterpriseCustomer: - fmt.Printf("serving enterprise customer %s\n", c.name) - case *IndividualCustomer: - fmt.Printf("serving individual customer %s\n", c.name) - } -} - -// only for enterprise -type AnalysisVisitor struct{} - -func (*AnalysisVisitor) Visit(customer Customer) { - switch c := customer.(type) { - case *EnterpriseCustomer: - fmt.Printf("analysis enterprise customer %s\n", c.name) - } +// clothFactory 服务装类工厂,购买汽油,制造化纤物品 +type clothFactory struct{} + +//Visit 购买汽油 +func (c *clothFactory) Visit(g gas) { + fmt.Println("clothFactory: use gas with density", g.density) } diff --git a/behavior/07_visitor/visitor_test.go b/behavior/07_visitor/visitor_test.go index 58f1d83..09056a2 100644 --- a/behavior/07_visitor/visitor_test.go +++ b/behavior/07_visitor/visitor_test.go @@ -1,15 +1,24 @@ package visitor -func ExampleRequestVisitor() { - c := &CustomerCol{} - c.Add(NewEnterpriseCustomer("A company")) - c.Add(NewEnterpriseCustomer("B company")) - c.Add(NewIndividualCustomer("bob")) - c.Accept(&ServiceRequestVisitor{}) - // Output: - // serving enterprise customer A company - // serving enterprise customer B company - // serving individual customer bob +import "testing" + +func TestVisitor(t *testing.T) { + + //汽油提供给,制衣工厂 + g := gas{density: 100} + + //柴油,提供给军工厂 + d := diesel{energy: 897} + + //购买石油的客户 + m := &militaryFactory{} + + c := &clothFactory{} + + g.Accept(c) + + d.Accept(m) + } func ExampleAnalysis() {