访问者模式

11.1 模式动机

访问者模式可以给一系列对象透明的添加功能,并且把相关代码封装到一个类中。

对象只要预留访问者接口Accept则后期为对象添加功能的时候就不需要改动对象。

10.2 Go语言实现

visitor.go

  1. package visitor
  2. import "fmt"
  3. type Customer interface {
  4. Accept(Visitor)
  5. }
  6. type Visitor interface {
  7. Visit(Customer)
  8. }
  9. type EnterpriseCustomer struct {
  10. name string
  11. }
  12. type CustomerCol struct {
  13. customers []Customer
  14. }
  15. func (c *CustomerCol) Add(customer Customer) {
  16. c.customers = append(c.customers, customer)
  17. }
  18. func (c *CustomerCol) Accept(visitor Visitor) {
  19. for _, customer := range c.customers {
  20. customer.Accept(visitor)
  21. }
  22. }
  23. func NewEnterpriseCustomer(name string) *EnterpriseCustomer {
  24. return &EnterpriseCustomer{
  25. name: name,
  26. }
  27. }
  28. func (c *EnterpriseCustomer) Accept(visitor Visitor) {
  29. visitor.Visit(c)
  30. }
  31. type IndividualCustomer struct {
  32. name string
  33. }
  34. func NewIndividualCustomer(name string) *IndividualCustomer {
  35. return &IndividualCustomer{
  36. name: name,
  37. }
  38. }
  39. func (c *IndividualCustomer) Accept(visitor Visitor) {
  40. visitor.Visit(c)
  41. }
  42. type ServiceRequestVisitor struct{}
  43. func (*ServiceRequestVisitor) Visit(customer Customer) {
  44. switch c := customer.(type) {
  45. case *EnterpriseCustomer:
  46. fmt.Printf("serving enterprise customer %s\n", c.name)
  47. case *IndividualCustomer:
  48. fmt.Printf("serving individual customer %s\n", c.name)
  49. }
  50. }
  51. // only for enterprise
  52. type AnalysisVisitor struct{}
  53. func (*AnalysisVisitor) Visit(customer Customer) {
  54. switch c := customer.(type) {
  55. case *EnterpriseCustomer:
  56. fmt.Printf("analysis enterprise customer %s\n", c.name)
  57. }
  58. }

visitor_test.go

  1. package visitor
  2. func ExampleRequestVisitor() {
  3. c := &CustomerCol{}
  4. c.Add(NewEnterpriseCustomer("A company"))
  5. c.Add(NewEnterpriseCustomer("B company"))
  6. c.Add(NewIndividualCustomer("bob"))
  7. c.Accept(&ServiceRequestVisitor{})
  8. // Output:
  9. // serving enterprise customer A company
  10. // serving enterprise customer B company
  11. // serving individual customer bob
  12. }
  13. func ExampleAnalysis() {
  14. c := &CustomerCol{}
  15. c.Add(NewEnterpriseCustomer("A company"))
  16. c.Add(NewIndividualCustomer("bob"))
  17. c.Add(NewEnterpriseCustomer("B company"))
  18. c.Accept(&AnalysisVisitor{})
  19. // Output:
  20. // analysis enterprise customer A company
  21. // analysis enterprise customer B company
  22. }