Design pattern family - iterator pattern, adapter pattern

Posted by pup200 on Sun, 02 Jan 2022 07:21:28 +0100

Iterator mode

brief introduction

The so-called Iterator mode is the interface programming for Iterator. No matter how the underlying data structure and iterative algorithm change, the caller does not need to modify the code;

High cohesion and low coupling are the way of programming.

Generally, you rarely need to write this iterator mode yourself, which is used in Collection programming. In particular, if you want to insert and delete the collection elements during traversal, use the iterator. If you want to traverse the collection in a class, the collection class returns an iterator, and the iterator interface is used for programming traversal, Improve the maintainability and scalability of the whole system.

If you write the iterator pattern yourself, you usually develop the underlying framework, such as providing a data for external traversal, you can use the iterator pattern to encapsulate the iterator yourself.

Usage scenario

Set iteration, traversing elements.

Code example

package com.wc.designpattern.iterator;

import lombok.Data;

/**
 * Iterator mode
 */
public class IteratorPatternApplication {

    @Data
    static class Student {
        private String name;

        public Student(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }

    static class Classroom {
        private Student[] students;
        private int last = 0;

        public Classroom(int size) {
            this.students = new Student[size];
        }

        public Student getStudents(int index) {
            return students[index];
        }

        public void addStudents(Student students) {
            this.students[last] = students;
            last ++;
        }

        public int getLength() {
            return last;
        }

        public Iterator iterator() {
            return new ClassroomIterator(this);
        }
    }

    public interface Iterator {
        boolean hasNext();
        Object next();
    }

    static class ClassroomIterator implements Iterator {
        private Classroom classroom;
        private int index;

        public ClassroomIterator(Classroom classroom) {
            this.classroom = classroom;
            this.index = 0;
        }

        @Override
        public boolean hasNext() {
            if (index < classroom.getLength()) {
                return true;
            } else {
                return false;
            }
        }

        @Override
        public Object next() {
            Student student = classroom.getStudents(index);
            index ++;
            return student;
        }
    }

    public static void main(String[] args) {
        Student s1 = new Student("lilei");
        Student s2 = new Student("hanmeimei");

        Classroom classroom = new Classroom(2);
        classroom.addStudents(s1);
        classroom.addStudents(s2);

        Iterator iterator = classroom.iterator();
        while (iterator.hasNext()) {
            Student student = (Student) iterator.next();
            System.out.println(student);
        }
    }
}

test

Execute the Main function to get the execution result

Student{name='lilei'}
Student{name='hanmeimei'}

Process finished with exit code 0

Adapter mode

brief introduction

The adapter mode is generally used in the process of continuous system upgrading. For the old code that has been written, write a set of adapters to adapt, but provide new interfaces.

In another case, for the existing third-party class libraries, such as redis clients or elasticsearch clients, they provide a set of API s, but our requirement here is to program for our DAO interface. At this time, you can write an adapter to adapt the interface of redis clients to our interface.

Usage scenario

(1) Suppose we make a first version of a system with an interface and an implementation class

(2) Then we started to make the second version of the system. In this system, we defined a new interface and a new implementation class

(3) However, in the second version of the system, we should also use the old interface and class defined in the first version of the system

Code example

Design patterns are not used

package com.wc.designpattern.adapter;

/**
 * If the iterator mode is not used, there will be the problem that the old and new interfaces cannot be adapted
 * It may be necessary to call multiple sets of API s where they are used, but because they are new and old interfaces,
 * There will be a lot of repetitive code, which is not a good design.
 */
public class NonPatternApplication {

    public interface V1Interface {
        void v1Execute();
    }

    static class V1InterfaceImpl implements V1Interface {
        @Override
        public void v1Execute() {
            System.out.println("v1 operator...");
        }
    }

    public interface V2Interface {
        void v2Execute();
    }

    static class V2InterfaceImpl implements V2Interface {
        @Override
        public void v2Execute() {
            System.out.println("v2 operator...");
        }
    }

    public static void main(String[] args) {
        V1Interface v1 = new V1InterfaceImpl();
        V2Interface v2 = new V2InterfaceImpl();
        v1.v1Execute();
        v2.v2Execute();
    }
}

Use adapter mode

package com.wc.designpattern.adapter;

/**
 * Adapter mode
 * That is, you have two new and old interfaces and an implementation class of an old interface
 * But now the system should be developed for the new interface, and the implementation classes of the old interface can not be used directly, and can not be developed directly for the old interface
 * Develop an adapter from an old interface to a new interface
 * The adapter implements the new interface, but the adapter holds the reference of the old interface implementation class instance
 * The implementation of the new interface method of the adapter is based on the old method of the old interface implementation class
 * For the caller, as long as the adapter is used for development, it can be developed by facing the new interface, and the bottom layer uses the old interface to implement the class
 *
 * @author WenChao
 * @date 21/12/23
 */
public class AdapterPatternApplication {

    public interface V1Interface {
        void v1Execute();
    }

    static class V1InterfaceImpl implements V1Interface {
        @Override
        public void v1Execute() {
            System.out.println("v1 operator...");
        }
    }

    public interface V2Interface {
        void v2Execute();
    }

    static class V2InterfaceImpl implements V2Interface {
        @Override
        public void v2Execute() {
            System.out.println("v2 operator...");
        }
    }

    /**
     * Define an adapter class
     */
    static class V2Adapter implements V2Interface {
        private V1Interface v1Interface;

        public V2Adapter(V1Interface v1Interface) {
            this.v1Interface = v1Interface;
        }

        @Override
        public void v2Execute() {
         v1Interface.v1Execute();
        }
    }

    public static void main(String[] args) {
        V2Interface v1 = new V2Adapter(new V1InterfaceImpl());
        V2Interface v2 = new V2InterfaceImpl();
        v1.v2Execute();
        v2.v2Execute();
    }
}

test

v1 operator...
v2 operator...

Process finished with exit code 0

Topics: Design Pattern