Golang - Visitor Pattern

Golang - Visitor Pattern

The Gang of Four design patterns are widely used in software development. One of the most useful ones is the Visitor Pattern. In this article, we will discuss the Visitor Pattern in the context of Golang.

What is the Visitor Pattern?

The Visitor Pattern is a behavioral design pattern that allows us to separate an algorithm from an object structure on which it operates. It is useful when we have a complex object structure and we want to perform some operations on it without changing the classes of the objects in the structure.

How does it work?

The Visitor Pattern works by separating the algorithm from the object structure. To achieve this, we define an interface that represents the algorithm. This interface will have a method for each class in the object structure. Each method will take an instance of the class as an argument. The object structure will also have an interface that defines a method for accepting the visitor. This method will take an instance of the visitor interface as an argument. When the accept method is called, the visitor's corresponding method for the class will be called.

Example

Suppose we have a complex object structure that represents a company's employees. The structure consists of different classes such as Manager, Engineer, and Salesman. We want to calculate the total salary of all employees in the company. We can use the Visitor Pattern to achieve this.

First, we define the Visitor interface:

type Visitor interface {
    VisitManager(manager *Manager)
    VisitEngineer(engineer *Engineer)
    VisitSalesman(salesman *Salesman)
}

Next, we define the Employee interface that defines a method for accepting the visitor:

type Employee interface {
    Accept(visitor Visitor)
}

We then define the different classes in the object structure:

type Manager struct {
    Name string
    Salary float64
}

func (m *Manager) Accept(visitor Visitor) {
    visitor.VisitManager(m)
}

type Engineer struct {
    Name string
    Salary float64
}

func (e *Engineer) Accept(visitor Visitor) {
    visitor.VisitEngineer(e)
}

type Salesman struct {
    Name string
    Salary float64
}

func (s *Salesman) Accept(visitor Visitor) {
    visitor.VisitSalesman(s)
}

Finally, we define the ConcreteVisitor that implements the Visitor interface and performs the desired operation:

type SalaryCalculator struct {
    TotalSalary float64
}

func (s *SalaryCalculator) VisitManager(manager *Manager) {
    s.TotalSalary += manager.Salary
}

func (s *SalaryCalculator) VisitEngineer(engineer *Engineer) {
    s.TotalSalary += engineer.Salary
}

func (s *SalaryCalculator) VisitSalesman(salesman *Salesman) {
    s.TotalSalary += salesman.Salary
}

We can then use the Visitor Pattern to calculate the total salary of all employees:

func main() {
    employees := []Employee{
        &Manager{Name: "John", Salary: 5000},
        &Engineer{Name: "Mary", Salary: 4000},
        &Salesman{Name: "Bob", Salary: 3000},
    }

    calculator := &SalaryCalculator{}
    for _, employee := range employees {
        employee.Accept(calculator)
    }

    fmt.Println("Total salary:", calculator.TotalSalary)
}

Output:

Total salary: 12000

Conclusion

The Visitor Pattern is a powerful design pattern that allows us to separate an algorithm from an object structure. It can be useful in many scenarios where we have a complex object structure and we want to perform some operations on it without changing the classes of the objects in the structure. In Golang, we can easily implement the Visitor Pattern using interfaces and methods.


References

Did you find this article valuable?

Support Matthias Bruns by becoming a sponsor. Any amount is appreciated!