Visitor pattern of design pattern (Vistor)

Visitor schema definition

Visitor pattern encapsulates some operations applied to a data structure. Once these operations need to be modified, the data structure that accepts the operation can be saved unchanged. Visitor mode is suitable for systems with relatively stable data structure. It reduces the coupling between the data structure and the operations acting on the data structure, so that the operation set can be changed relatively freely.

Each node of the data structure can accept the call of a visitor. This node passes in the node object to the visitor object, and the visitor object in turn performs the operation of the node object. This process is called "double dispatch". The node calls the visitor and passes it in, and the visitor executes an algorithm for this node.

Represents an operation that acts on elements in an object structure. It allows you to define new operations on elements without changing their classes.

Structure division


It needs to be clear that the number of specific visitors in the visitor pattern has nothing to do with the number of specific nodes. As can be seen from the visitor's structure diagram, the visitor pattern involves the following types of roles.

  • Abstract visitor role (Vistor): an interface that declares one or more access operations so that all concrete visitors must implement.
  • Concrete visitor role: implements all declared interfaces in the abstract visitor role.
  • Abstract node role (Element): declare an accept operation and accept a visitor object as a parameter.
  • Concrete element: implement the acceptance operation specified by the abstract element.
  • Structure object role (ObjectStructure): the container of nodes, which can contain multiple containers with different classes or interfaces.

code implementation

	abstract class Visitor
    {
        public abstract void VisitConcreteElementA(ConcreteElementA concreteElementA);

        public abstract void VisitConcreteElementB(ConcreteElementB concreteElementB);
    }

    class ConcreteVisitor1 : Visitor
    {
        public override void VisitConcreteElementA(ConcreteElementA concreteElementA)
        {
            Console.WriteLine("{0}cover{1}visit", concreteElementA.GetType().Name, this.GetType().Name);
        }

        public override void VisitConcreteElementB(ConcreteElementB concreteElementB)
        {
            Console.WriteLine("{0}cover{1}visit", concreteElementB.GetType().Name, this.GetType().Name);
        }
    }

    class ConcreteVisitor2 : Visitor
    {
        public override void VisitConcreteElementA(ConcreteElementA concreteElementA)
        {
            Console.WriteLine("{0}cover{1}visit", concreteElementA.GetType().Name, this.GetType().Name);
        }

        public override void VisitConcreteElementB(ConcreteElementB concreteElementB)
        {
            Console.WriteLine("{0}cover{1}visit", concreteElementB.GetType().Name, this.GetType().Name);
        }
    }

    abstract class Element
    {
        public abstract void Accept(Visitor visitor);
    }

    class ConcreteElementA : Element
    {
        public override void Accept(Visitor visitor)
        {
            visitor.VisitConcreteElementA(this);
        }

        public void OperationA()
        { }
    }

    class ConcreteElementB : Element
    {
        public override void Accept(Visitor visitor)
        {
            visitor.VisitConcreteElementB(this);
        }

        public void OperationB()
        { }
    }

    class ObjectStructure
    {
        private IList<Element> elements = new List<Element>();

        public void Attach(Element element)
        {
            elements.Add(element);
        }

        public void Detach(Element element)
        {
            elements.Remove(element);
        }

        public void Accept(Visitor visitor)
        {
            foreach (Element e in elements)
            {
                e.Accept(visitor);
            }
        }
    }
		static void Main(string[] args)
        {
            ObjectStructure o = new ObjectStructure();
            o.Attach(new ConcreteElementA());
            o.Attach(new ConcreteElementB());

            ConcreteVisitor1 v1 = new ConcreteVisitor1();
            ConcreteVisitor2 v2 = new ConcreteVisitor2();

            o.Accept(v1);
            o.Accept(v2);

            Console.Read();
        }

Application scenario of visitor mode

Each design pattern has its own situation that should be used. Let's take a look at the specific application scenario of visitor pattern. If we encounter the following scenarios, we can consider using visitor mode at this time.

If the system has a relatively stable data structure and an algorithm that is easy to change, the visitor mode can be considered at this time. Because the visitor mode makes it easier to add algorithm operations.
If there are similar operations in a group of classes, in order to avoid a large number of repeated code, you can consider encapsulating the repeated operations into the visitor. (of course, you can also consider using abstract classes)
If an object has some operations that are irrelevant to its own object or have a weak relationship, in order to avoid polluting the object, you can consider encapsulating these operations into the visitor object.

Advantages and disadvantages of visitor mode

advantage:

Visitor mode makes it easy to add new operations. If some operations depend on a complex structure object, generally speaking, adding a new operation will become very complex. With visitor mode, adding a new operation means adding a new visitor class. Therefore, it is easy to add a new operation.
The visitor pattern enables the relevant behavior operations to be concentrated in one visitor object rather than scattered into one element class. This is similar to the "mediator model".
Visitor pattern can access member objects belonging to different hierarchical structures, while iteration can only access member objects belonging to the same hierarchical structure.
Disadvantages:

Adding new element classes becomes difficult. Adding a new element means adding a new abstract operation to the abstract visitor role, and adding the corresponding concrete operation to each concrete visitor class.

summary

Visitor pattern is used to encapsulate some operations imposed on a data structure. It makes it possible to add new operations on these elements without changing the elements themselves. The purpose of the visitor pattern is to separate the operations from the data structure.

Tags: C# Design Pattern

Posted on Sun, 26 Sep 2021 00:57:53 -0400 by Tensing