Visitor Pattern

Visitor mode

In real life, some collection objects have many different elements, and each element also has many different visitors and processing methods. For example, there are many scenic spots and tourists in the park. Different tourists may have different comments on the same scenic spot; The prescription list issued by the hospital doctor contains a variety of drug elements. The price assessors and pharmacy staff treat it differently. The price assessors price the drugs according to the name and quantity on the prescription list, and the pharmacy staff fill the drugs according to the content of the prescription list.

Visitor mode separates the operations that act on each element in a data structure and encapsulates them into independent classes, so that it can add new operations that act on these elements without changing the data structure, and provide a variety of access methods for each element in the data structure. It separates the data operation from the data structure. It is the most complex pattern in the behavior pattern.

Intention: mainly separate data structure from data operation.

Visitor pattern is an object behavior pattern. Its main advantages are as follows.

  • Good scalability. It can add new functions to the elements in the object structure without modifying the elements in the object structure.
  • Good reusability. Visitors can define the general functions of the whole object structure, so as to improve the reuse degree of the system.
  • Good flexibility. Visitor mode decouples the data structure from the operations acting on the structure, so that the operation set can evolve relatively freely without affecting the data structure of the system.
  • Comply with the principle of single responsibility. Visitor mode encapsulates the relevant behaviors to form a visitor, so that the function of each visitor is relatively single.

The main disadvantages of the Visitor pattern are as follows.

  • Adding new element classes is difficult. In the visitor mode, every time a new element class is added, the corresponding specific operation must be added to each specific visitor class, which violates the "opening and closing principle".
  • Destroy the package. In the visitor pattern, specific elements publish details to visitors, which destroys the encapsulation of objects.
  • It violates the principle of inversion of dependence. The visitor pattern relies on concrete classes rather than abstract classes.

The class diagram is as follows.

The complete code is as follows.

using System;
using System.Collections.Generic;

namespace _22_Visitor
{
    class Program
    {
        static void Main(string[] args)
        {
            //Visitor is a behavior design pattern that allows you to add new behaviors to the existing class hierarchy without modifying the existing code.
            List<IComponent> components = new List<IComponent> { 
            new ConcreteComponentA(),
            new ConcreteComponentB()
            };
            Console.WriteLine("The client code works with all visitors via the base Visitor interface:");
            var visitor1 = new ConcreteVisitor1();
            Client.ClientCode(components, visitor1);
            Console.WriteLine();
            Console.WriteLine("It allows the same client code to work with different types of visitors:");
            var visitor2 = new ConcreteVisitor2();
            Client.ClientCode(components, visitor2);
            Console.ReadKey();
        }
    }
    public interface IComponent
    {
        void Accept(IVisitor visitor);
    }
    public class ConcreteComponentA : IComponent
    {
        public void Accept(IVisitor visitor)
        {
            visitor.VisitConcreteComponentA(this);
        }
        public string ExclusiveMethodOfConcreteComponentA()
        {
            return "A";
        }
    }
    public class ConcreteComponentB : IComponent
    {
        public void Accept(IVisitor visitor)
        {
            visitor.VisitConcreteComponentB(this);
        }
        public string SpecialMethodOfConcreteComponentB()
        {
            return "B";
        }
    }
    public interface IVisitor
    {
        void VisitConcreteComponentA(ConcreteComponentA element);
        void VisitConcreteComponentB(ConcreteComponentB element);
    }
    class ConcreteVisitor1 : IVisitor
    {
        public void VisitConcreteComponentA(ConcreteComponentA element)
        {
            Console.WriteLine(element.ExclusiveMethodOfConcreteComponentA() + " + ConcreteVisitor1");
        }
        public void VisitConcreteComponentB(ConcreteComponentB element)
        {
            Console.WriteLine(element.SpecialMethodOfConcreteComponentB() + " + ConcreteVisitor1");
        }
    }
    class ConcreteVisitor2 : IVisitor
    {
        public void VisitConcreteComponentA(ConcreteComponentA element)
        {
            Console.WriteLine(element.ExclusiveMethodOfConcreteComponentA() + " + ConcreteVisitor2");
        }

        public void VisitConcreteComponentB(ConcreteComponentB element)
        {
            Console.WriteLine(element.SpecialMethodOfConcreteComponentB() + " + ConcreteVisitor2");
        }
    }
    public class Client
    {
        public static void ClientCode(List<IComponent> components,IVisitor visitor)
        {
            foreach (var component in components)
            {
                component.Accept(visitor);
            }
        }
    }
}

Keywords: C# Design Pattern

Added by mikeoffy69 on Tue, 08 Mar 2022 01:50:23 +0200