Design pattern learning - using go to implement visitor pattern

Posted by kungfu71186 on Fri, 26 Nov 2021 20:16:10 +0100

Visitor mode

definition

Visitor pattern: represents an operation that acts on elements in an object structure. It allows you to define new operations on these elements without changing the element class.

Using the visitor pattern, the execution algorithm of the element can change as the visitor changes. The main intention is to separate data structure from data operation.

However, as one of the more difficult to understand design patterns, because it is difficult to understand and implement, the application of it will lead to the poor readability and maintainability of the code. Therefore, the visitor pattern is rarely used in the actual software development, and the visitor pattern is not recommended when it is not particularly necessary.

advantage

1. Opening and closing principle. You can introduce new behaviors that execute on different kinds of objects without modifying these classes.

2. Single responsibility principle. Different versions of the same behavior can be moved to the same class.

3. Better flexibility.

shortcoming

1. It is difficult to change specific elements. Every time a class is added or removed from the element hierarchy, all visitors are updated.

2. It is difficult to understand. Applying it will lead to poor readability and maintainability of the code.

Scope of application

1. The class corresponding to the object in the object structure rarely changes, but it is often necessary to define new operations on this object structure.

2. You need to perform many different and irrelevant operations on objects in an object structure. You need to avoid these operations "polluting" the classes of these objects, and you don't want to modify these classes when adding new operations.

code implementation

Code implementation:

type Visitor interface {
	VisitConcreteElementA(cea *ConcreteElementA)
	VisitConcreteElementB(ceb *ConcreteElementB)
}

type ConcreteVisitor1 struct {
}

func (cea *ConcreteVisitor1) VisitConcreteElementA(concreteElementA *ConcreteElementA) {
	fmt.Println("concreteVisitor1 visitConcreteElementA")
}

func (*ConcreteVisitor1) VisitConcreteElementB(concreteElementB *ConcreteElementB) {
	fmt.Println("concreteVisitor1 visitConcreteElementB")
}

type ConcreteVisitor2 struct {
}

func (*ConcreteVisitor2) VisitConcreteElementA(concreteElementA *ConcreteElementA) {
	fmt.Println("concreteVisitor2 visitConcreteElementA")
}

func (*ConcreteVisitor2) VisitConcreteElementB(concreteElementB *ConcreteElementB) {
	fmt.Println("concreteVisitor2 visitConcreteElementB")
}

type Element interface {
	Accept(visitor Visitor)
}

type ConcreteElementA struct {
}

func (cea *ConcreteElementA) Accept(visitor Visitor) {
	visitor.VisitConcreteElementA(cea)
}

type ConcreteElementB struct {
}

func (ceb *ConcreteElementB) Accept(visitor Visitor) {
	visitor.VisitConcreteElementB(ceb)
}

Test code:

func TestVisitor(t *testing.T) {
	var elements []Element
	elements = append(elements, &ConcreteElementA{})
	elements = append(elements, &ConcreteElementB{})

	for _, item := range elements {
		cv1 := &ConcreteVisitor1{}
		cv2 := &ConcreteVisitor2{}
		item.Accept(cv1)
		item.Accept(cv2)
	}
}

Structure diagram:

What is Double Dispatch

What is dispatch?

Dispatch is dispatch. In object-oriented programming language, we can understand method call as a kind of message passing (dispatch). When an object calls a method of another object, it is equivalent to sending a message to the called object. This message includes object name, method name, method parameters and other information.

What is single dispatch?

Single dispatch, that is, the method of which object to execute, is determined according to the runtime type of the object; Which method of the object to execute depends on the compile time type of the method parameter.

What is double dispatch?

Double dispatch, that is, the method of which object to execute, is determined according to the runtime type of the object; Which method of the object to execute depends on the runtime type of the method parameter.

Specific to the syntax mechanism of programming language, Single Dispatch and Double Dispatch are directly related to polymorphism and function overloading. So go does not support Double Dispatch.

The current mainstream object-oriented programming languages (such as Java, C + +, c#) only support Single Dispatch and do not support Double Dispatch.

Using java to lift chestnuts is easier to understand:

import java.util.ArrayList;
import java.util.List;

abstract class ResourceFile {
    protected String filePath;

    public ResourceFile(String filePath) {
        this.filePath = filePath;
    }
}

class PdfFile extends ResourceFile {
    public PdfFile(String filePath) {
        super(filePath);
    }
}

class PPTFile extends ResourceFile {
    public PPTFile(String filePath) {
        super(filePath);
    }
}

//... PPTFile, WordFile code omitted
class Extractor {

    public void extract2txt(PdfFile pdfFile) {
        System.out.println("Extract PDF.");
    }

    public void extract2txt(PPTFile ppTFile) {
        System.out.println("Extract PPT.");
    }
}

public class Test {
    public static void main(String[] args) {
        Extractor extractor = new Extractor();
        List<ResourceFile> resourceFiles = listAllResourceFiles();

        for (ResourceFile resourceFile : resourceFiles) {
            extractor.extract2txt(resourceFile);
        }
    }

    private static List<ResourceFile> listAllResourceFiles() {
        List<ResourceFile> resourceFiles = new ArrayList<>();
        //... create different class objects (PdfFile/PPTFile/WordFile) by factory methods according to the suffix (pdf/ppt/word)
        resourceFiles.add(new PPTFile("a.ppt"));
        resourceFiles.add(new PdfFile("a.pdf"));

        return resourceFiles;
    }
}

For example, this code will be in extractor.extract2txt(resourceFile);, At runtime, the code will decide which of the three overloaded functions of extract2txt to use according to the actual type of the parameter (resourceFile) (PdfFile, PPTFile, WordFile). Then the following code implementation can run normally.

Error message

java: about extract2txt(ResourceFile), No suitable method was found
    method Extractor.extract2txt(PdfFile)Not applicable
      (Parameter mismatch; ResourceFile Cannot convert to PdfFile)
    method Extractor.extract2txt(PPTFile)Not applicable
      (Parameter mismatch; ResourceFile Cannot convert to PPTFile)

reference resources

[code in text] https://github.com/boilingfrog/design-pattern-learning/tree/master/ Visitor mode
[big talk design mode] https://book.douban.com/subject/2334288/
[geek time] https://time.geekbang.org/column/intro/100039001
[double dispatch - past and present life of visitor mode] https://www.codenong.com/cs110749395/
[visitor mode] https://boilingfrog.github.io/2021/11/25/ Implementing visitor pattern with go/

Topics: computer networks