Software design patterns (6): iterator, visitor, builder patterns

Preface

        In this article, Lizhi will introduce relevant knowledge about iterator pattern, visitor pattern and builder pattern. Among them, iterator and builder are relatively used more, and visitor pattern is relatively less used. . The key point is to understand the characteristics of different modes~ I hope it can help friends in need~~~


Article directory

Preface

1. Iterator pattern Iterator

2. Visitor mode Visitor

3. Builder mode Builder

Summarize


1. Iterator pattern Iterator

        The iterator pattern is generally used for containers and container traversal. The iterator pattern is generally adopted at the bottom of the basic data structure. The application of the iterator pattern is to provide us with a method to sequentially access each element in an aggregate object without explicit traversal logic inside the object.

In order to better understand this software design pattern, let’s take a look at this set of demos:

First create two interfaces, one is the iterator interface Iterator_, the other is the total interface Collection_ of the data structure

        Define two more container classes ArrayList_ and LinkedList_. These two classes implement the Collection_ interface. This interface defines operations for adding data in the container, obtaining the size of the container, and providing traversal through the methods of the Iterator interface . interface methods . Two container classes are obtained by implementing the Collection_ interface and overriding the methods in this interface.

ArrayList_ 

package com.crj.Iterator;

class ArrayList_ implements Collection_ {
    Object[] objects = new Object[10];
    //objects中下一个空的位置在哪儿,或者说,目前容器中有多少个元素
    private int index = 0;
    public void add(Object o) {
        if(index == objects.length) {
            Object[] newObjects = new Object[objects.length*2];
            System.arraycopy(objects, 0, newObjects, 0, objects.length);
            objects = newObjects;
        }

        objects[index] = o;
        index ++;
    }

    public int size() {
        return index;
    }

    @Override
    public Iterator_ iterator() {
        return new ArrayListIterator();
    }

    private class ArrayListIterator implements Iterator_{

        private int currentIndex = 0;

        @Override
        public boolean hasNext() {
            if(currentIndex >= index) return false;
            return true;
        }

        @Override
        public Object next() {
            Object o = objects[currentIndex];
            currentIndex ++;
            return o;
        }
    }
}

LinkedList_ 

package com.crj.Iterator;

/**
 * 相比数组,这个容器不用考虑边界问题,可以动态扩展
 */
class LinkedList_ implements Collection_ {
    Node head = null;
    Node tail = null;
    //目前容器中有多少个元素
    private int size = 0;

    public void add(Object o) {
        Node n = new Node(o);
        n.next = null;

        if(head == null) {
            head = n;
            tail = n;
        }

        tail.next = n;
        tail = n;
        size++;
    }

    private class Node {
        private Object o;
        Node next;

        public Node(Object o) {
            this.o = o;
        }
    }

    public int size() {
        return size;
    }

    @Override
    public Iterator_ iterator() {
        return null;
    }
}

main class

package com.crj.Iterator;

import java.util.Iterator;

public class Main {
    public static void main(String[] args) {
        Collection_ list = new ArrayList_();
        for(int i=0; i<15; i++) {
            list.add(new String("s" + i));
        }
        System.out.println(list.size());

        //这个接口的调用方式:
        Iterator_ it = list.iterator();
        while(it.hasNext()) {
            Object o = it.next();
            System.out.println(o);
        }
    }
}

        In main, we can see that we do not need to know the logic encapsulated in the two container classes and the corresponding logic implementation of traversing the internal elements of the container. We only need to use the pointer-like iterator method like .next(). You can get the elements in the container, which is the iterator pattern.


2. Visitor mode Visitor

        To dynamically change the mode of internal element action while the structure remains unchanged, the Visitor mode is more suitable for the use of class objects with unchanged structure. The classes corresponding to the objects in the object structure rarely change, but it is often necessary to define new ones on this object structure. operation. The visitor mode is rarely used in daily use. One of its main application scenarios is to be a compiler. This mode is relatively simple to understand. Let's understand it through some code examples.

public class VisitorPatternDemo {
   public static void main(String[] args) {
 
      ComputerPart computer = new Computer();
      computer.accept(new ComputerPartDisplayVisitor());
   }
}
/*
* 接口
*/
interface ComputerPart {
   public void accept(ComputerPartVisitor computerPartVisitor);
}
/*
* 接口实现类
*/
class Keyboard  implements ComputerPart {
   @Override
   public void accept(ComputerPartVisitor computerPartVisitor) {
      computerPartVisitor.visit(this);
   }
}
class Mouse  implements ComputerPart {
   @Override
   public void accept(ComputerPartVisitor computerPartVisitor) {
      computerPartVisitor.visit(this);
   }
}
/*
* 访问者接口
*/
interface ComputerPartVisitor {
   public void visit(Mouse mouse);
   public void visit(Keyboard keyboard);
}
//实现类
class ComputerPartDisplayVisitor implements ComputerPartVisitor {

   @Override
   public void visit(Mouse mouse) {
      System.out.println("Displaying Mouse.");
   }
 
   @Override
   public void visit(Keyboard keyboard) {
      System.out.println("Displaying Keyboard.");
   }
}

Different visitor interfaces provide corresponding implementation classes. By passing the visitor interface implementation class instantiation object into the instantiation method of ComputerPart, the corresponding method of the interface is called.


3. Builder mode Builder

        The Builder Pattern uses multiple simple objects to build a complex object step by step. Targeted scenario: Many parameters need to be passed in the construction method of a class object. In order to abbreviate the demo, we can generate multiple objects through chain calls to obtain the final construction of complex class objects. We can understand through a demo example:

First define a TerrainBuilder interface, which defines four interface methods

package com.crj.builder;

public interface TerrainBuilder {
    TerrainBuilder buildWall();
    TerrainBuilder buildFort();
    TerrainBuilder buildMine();
    Terrain build();
}

Then define the implementation class of the interface. This interface implementation class implements the TerrainBuilder interface. In the demo, the four interface methods are rewritten. Finally, the terrain object is returned in the build() method.

package com.crj.builder;

public class ComplexTerrainBuilder implements TerrainBuilder {
    Terrain terrain = new Terrain();

    @Override
    public TerrainBuilder buildWall() {
        terrain.w = new Wall(10, 10, 50, 50);
        return this;
    }

    @Override
    public TerrainBuilder buildFort() {
        terrain.f = new Fort(10, 10, 50, 50);
        return this;
    }

    @Override
    public TerrainBuilder buildMine() {
        terrain.m = new Mine(10, 10, 50, 50);
        return this;
    }

    @Override
    public Terrain build() {
        return terrain;
    }
}

Object class

package com.crj.builder;

public class Terrain {
    Wall w;
    Fort f;
    Mine m;
}
class Wall {
    int x, y, w, h;

    public Wall(int x, int y, int w, int h) {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
    }
}
class Fort {
    int x, y, w, h;

    public Fort(int x, int y, int w, int h) {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
    }

}
class Mine {
    int x, y, w, h;

    public Mine(int x, int y, int w, int h) {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
    }
}

Define main class

package com.crj.builder;

public class Main {
    public static void main(String[] args) {
        TerrainBuilder builder = new ComplexTerrainBuilder();
        Terrain t = builder.buildFort().buildMine().buildWall().build();
    }
}

In the main class, we can see that the instantiation of the Terrain class object is achieved by means of a series of chain calls instead of the traditional call to the parameterized constructor. 


Summarize

For design patterns, we actually need to understand the theory, and there is no need to distinguish them in particular, because different software code patterns often contain multiple design patterns. Learning design patterns is still quite boring haha. After sorting out the output, I hope Lizhi will not forget it so quickly hahaha

Today has become the past, but we still look forward to the future tomorrow! I am Xiaolizhi, and I will accompany you on the road of technological growth. Coding is not easy, so please raise your little paw and give me a thumbs up, hahaha~~~ Bixinxin♥~~~

Guess you like

Origin blog.csdn.net/qq_62706049/article/details/132782793