访问者模式(Visitor)
1.意图
表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
2.适用性
在下列情况下使用Visitor模式:
- 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Visitor使得你可以将相关的操作集中起来定义在一个类中。当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。
- 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。
3.结构
4.代码
package visitor
import "testing"
/*
# 访问者模式
访问者模式可以给一系列对象透明的添加功能,并且把相关代码封装到一个类中。
对象只要预留访问者接口`Accept`则后期为对象添加功能的时候就不需要改动对象。
*/
type Visitor interface {
VisitCPU(cpu CPU)
VisitMemory(memory Memory)
VisitBoard(board Board)
}
type ComputerPart interface {
Accept(visitor Visitor)
//some other operations eg:getName getBrand
GetPrice()float64
}
type CPU struct {
ComputerPart
}
func (this CPU)Accept(visitor Visitor){
visitor.VisitCPU(this)
}
func (this CPU)GetPrice()float64{
return 500
}
type Memory struct {
ComputerPart
}
func (this Memory)Accept(visitor Visitor){
visitor.VisitMemory(this)
}
func (this Memory)GetPrice()float64{
return 300
}
type Board struct {
ComputerPart
}
func (this Board)Accept(visitor Visitor){
visitor.VisitBoard(this)
}
func (this Board)GetPrice()float64{
return 200
}
type Computer struct {
cpu CPU
memory Memory
board Board
}
func (this *Computer)Accept(visitor Visitor){
this.cpu.Accept(visitor)
this.memory.Accept(visitor)
this.board.Accept(visitor)
}
type PersonelVisitor struct {
TotalPrice float64
Visitor
}
func (this *PersonelVisitor)VisitCPU(cpu CPU) {
this.TotalPrice += cpu.GetPrice()*0.9
}
func (this *PersonelVisitor)VisitMemory(memory Memory) {
this.TotalPrice += memory.GetPrice()*0.85
}
func (this *PersonelVisitor)VisitBoard(board Board) {
this.TotalPrice += board.GetPrice()*0.9
}
type CorpVisitor struct {
TotalPrice float64
Visitor
}
func (this *CorpVisitor)VisitCPU(cpu CPU) {
this.TotalPrice += cpu.GetPrice()*0.6
}
func (this *CorpVisitor)VisitMemory(memory Memory) {
this.TotalPrice += memory.GetPrice()*0.75
}
func (this *CorpVisitor)VisitBoard(board Board) {
this.TotalPrice += board.GetPrice()*0.75
}
func TestVisitor(t *testing.T) {
p0:=&PersonelVisitor{}
p1:=&CorpVisitor{}
c:=Computer{}
c.Accept(p0)
c.Accept(p1)
t.Log("Personel购买价格:",p0.TotalPrice)
t.Log("Corp购买价格:", p1.TotalPrice)
}
//type Customer interface {
// Accept(Visitor)
//}
//
//type Visitor interface {
// Visit(Customer)
//}
//
//
//type EnterpriseCustomer struct {
// name string
//}
//
//type CustomerCol struct {
// customers []Customer
//}
//
//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)
// }
//}
//
//
//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
//}
//
//func ExampleAnalysis() {
// c := &CustomerCol{}
// c.Add(NewEnterpriseCustomer("A company"))
// c.Add(NewIndividualCustomer("bob"))
// c.Add(NewEnterpriseCustomer("B company"))
// c.Accept(&AnalysisVisitor{})
// // Output:
// // analysis enterprise customer A company
// // analysis enterprise customer B company
//}