Complete summary of 23 Java design patterns | Packaged please take away

Posted by PrivatePile on Tue, 11 Feb 2020 05:35:50 +0100

Design pattern s are a set of repetitive, well-known, categorized, code design experiences.

There are three types of design patterns, 23 of which are:

GitHub: youlookwhat/DesignPattern

Refer to articles written by Hong Yang, Newbie Tutorial, etc.If there are any errors, please correct them. If there are any infringements, please contact me to delete them.

Blog Catalogue:

Source Code

Project Picture


Pattern Analysis

1. Observer mode

Defines a one-to-many dependency between objects so that when an object changes, all its dependents are notified and updated automatically.

  • For JDK or Andorid, there are many places where observer mode is implemented, such as XXXView.addXXXListener, of course XXXView.setOnXXXListener is not necessarily observer mode, because observer mode is a one-to-many relationship, and setXXXListener is a one-to-one relationship, which should be called callback.

  • Thematic interface: Subject.java ;

    /**
     * Register an observer
     */
    public void registerObserver(Observer observer);
    
    /**
     * Remove an observer
     */
    public void removeObserver(Observer observer);
    
    /**
     * Notify all observers
     */
    public void notifyObservers();
    
  • Implementation class for 3D service number: ObjectFor3D.java

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }
    @Override
    public void removeObserver(Observer observer) {
        int index = observers.indexOf(observer);
        if (index >= 0) {
            observers.remove(index);
        }
    }
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(msg);
        }
    }
    /**
     * Topic Update Information
     */
    public void setMsg(String msg) {
        this.msg = msg;
        notifyObservers();
    }
    
  • All observers need to implement this interface: Observer.java

     public ObserverUser1(Subject subject) {
        subject.registerObserver(this);
    }
    @Override
    public void update(String msg) {
        Log.e("-----ObserverUser1 ", "Get 3 D number:" + msg + ", I want to write it down.");
    }
    
  • Last test: ObserverActivity.java

    // Create Service Number
    objectFor3D = new ObjectFor3D();
    // Create two subscribers
    observerUser1 = new ObserverUser1(objectFor3D);
    observerUser2 = new ObserverUser2(objectFor3D);
    // Two observers, sending two messages
    objectFor3D.setMsg("201610121 3 D be entitled as:127");
    objectFor3D.setMsg("20161022 3 D be entitled as:000");
    

2. Factory Mode

To briefly list the families of this pattern:

  • 1. Static Factory Mode

    • This is the most common, auxiliary class in a project, TextUtil.isEmpty, etc., class + static method.
  • 2. Simple Factory Mode (Buy meat clips in stores)

    • Definition: Create instances of other classes by specifically defining one class. The instances created usually have a common parent class.
    • Create meat clips directly according to type: SimpleRoujiaMoFactory.java
    public RoujiaMo creatRoujiaMo(String type) {
        RoujiaMo roujiaMo = null;
        switch (type) {
            case "Suan":
                roujiaMo = new ZSuanRoujiaMo();
                break;
            case "La":
                roujiaMo = new ZLaRoujiaMo();
                break;
            case "Tian":
                roujiaMo = new ZTianRoujiaMo();
                break;
            default:// Default to sour meat bun
                roujiaMo = new ZSuanRoujiaMo();
                break;
        }
        return roujiaMo;
    }
    
  • 3. Factory method mode (opening a branch)

    • Definition: Defines an interface for creating objects, but subclasses determine which class to instantiate.The factory method pattern defers class instantiation to subclasses.
    • Definition of comparison:
    • 1. An interface for creating objects is defined: public abstract RouJiaMo sellRoujiaMo(String type);
    • 2. The instantiated classes are determined by the subclasses. You can see that our buns are generated by the subclasses.
  • Provides an abstract way to create a meat clip bun store: RoujiaMoStore.java

    public abstract RoujiaMo sellRoujiaMo(String type);
    
  • Implement abstract methods specifically: XianRoujiaMoStore.java

  • Branches still use the simple factory model: XianSimpleRoujiaMoFactory.java

  • 4. Abstract Factory Mode (using officially supplied raw materials)

    • Definition: Provides an interface for creating a family of related or dependent objects without explicitly specifying a specific class.
    • Definition of comparison:
      • 1. Provide an interface: public interface RouJiaMoYLFactroy
      • 2. Family public Meat createMeat();public YuanLiao createYuanliao(); our interface is used to create a series of raw materials.
    • Create an interface factory to supply raw materials: RoujiaMoYLFactory.java
    • Each branch implements interfaces to complete the supply of raw materials: XianRoujiaMoYLFoctory.java
    • When preparing, use official ingredients: RoujiaMo.java
    /**
    * Dead work
    */
    public void prepare(RoujiaMoYLFactory roujiaMoYLFactory) {
       	Meet meet = roujiaMoYLFactory.creatMeet();
       	YuanLiao yuanLiao = roujiaMoYLFactory.creatYuanLiao();
       	Log.e("---RoujiaMo:", "Use official ingredients ---" + name + ": Kneading dough-Minced meat-Complete Preparations yuanLiao:"+meet+"yuanLiao:"+yuanLiao);
    }
    

3. Single Case Design Mode

Singleton mode is designed to avoid wasting resources by creating multiple instances, and multiple instances are prone to errors due to multiple calls. Using singleton mode ensures that there is only one instance in the entire application.

  • Definition: Only three steps are required to ensure the uniqueness of the object

    • (1) Do not allow other programs to use new objects
    • (2) Create objects in this class
    • (3) Provide a method for other programs to obtain the object
  • Definition of comparison:

    • (1) Privateize the constructor for this class
    • (2) Create an object of this class from new
    • (3) Define a public method that returns the objects created in that class
  • Hungry Han style [available]: SingletonEHan.java

  • Lazy man style [recommended for double check locks]: SingletonLanHan.java

    private SingletonLanHan() {}
    private static SingletonLanHan singletonLanHanFour;
    public static SingletonLanHan getSingletonLanHanFour() {
   	    if (singletonLanHanFour == null) {
   		synchronized (SingletonLanHan.class) {
   		    if (singletonLanHanFour == null) {
   			singletonLanHanFour = new SingletonLanHan();
   		    }
   		}
   	    }
   	    return singletonLanHanFour;
   }
   

4. Policy Patterns

Strategy mode: A family of algorithms is defined and encapsulated so that they can be replaced with each other. This mode makes the algorithm change independent of the customers using the algorithm.

  • Take creating game roles as an example:
    • The parent of the original game character: Role.java
    • When duplicate code is found, the refactored parent class: Role.java
  • Summary:
    • 1. Encapsulate changes (encapsulate potentially changing code)
    • 2. Use combinations more than inheritance (we use combinations to set up algorithms for our clients)
    • 3. Programming for interfaces, not for implementations (Role class design is entirely role-specific, not related to skill achievement)
  • Last test: Create roles:
RoleA roleA = new RoleA("---A");
roleA.setiDisplayBehavior(new DisplayYZ())
      .setiAttackBehavior(new AttackXL())
      .setiDefendBehavior(new DefendTMS())
      .setiRunBehavior(new RunJCTQ());
roleA.display();// A look
roleA.attack();// attack
roleA.run();// escape
roleA.defend();// defense

5. Adapter mode

Definition: Converts the interface of one class to another that the client expects, and the adapter allows classes that are incompatible with the original interface to cooperate with each other.That's a good definition. An adapter's function is to convert one interface into another.

  • Take the charger as an example: mobile phone chargers are generally around 5V, our home AC voltage is 220V, so mobile phone charging requires an adapter (pressure reducer)

  • A mobile phone: Mobile.java

  • The phone relies on an interface that provides 5V voltage: V5Power.java

  • We have 220V home AC: V220Power.java

  • Adapter for 220V to 5V: V5PowerAdapter.java

  • Last test: power your phone:

    Mobile mobile = new Mobile();
    V5Power v5Power = new V5PowerAdapter(new V200Power());
    mobile.inputPower(v5Power);
    

6. Command mode

Definition: Encapsulate a Request as an object to parameterize other objects using different requests, queues, or logs.Command mode also supports undoable operations.(simplification: encapsulate the request as an object and decouple the action requestor from the action executor.)

  • Requirements: Recently, smart home appliances are hot. Assuming there are TV, computer, lamp and other home appliances now, you need to make a remote control to control the switches of all home appliances. You need to make the functions corresponding to each button personalized for users, and have a very strong scalability for newly purchased home appliances.
  • 1. API for home appliances: Door.java
  • 2. Encapsulate commands into classes:
  • 3. Remote control: ControlPanel.java
  • 4. Define a command that does a series of things: QuickCommand.java
QuickCommand quickCloseCommand = new QuickCommand(new Command[]{new LightOffCommand(light), new ComputerOffCommand(computer), new DoorCloseCommand(door)});
controlPanel.setCommands(6, quickOpenCommand);
controlPanel.keyPressed(6);
controlPanel.setCommands(0, new DoorOpenCommand(door));// Open the door
controlPanel.keyPressed(0);

7. Decorator Mode

Decorator mode: To extend functionality, the decorator provides a more flexible alternative to integration, dynamically attaching responsibility to the object.

  • Let's start with a brief description of where the Decorator mode works. When we have designed a class, we need to add some auxiliary functions to it and don't want to change the code of this class. It's time for the Decorator mode to take on its grandeur.There is also a principle that classes should be open to extensions and closed to modifications.

  • Requirements: Design game equipment systems, basic requirements, to be able to calculate the attack power and description of each kind of equipment after various gems are inlaid:

  • 1. Superclass of equipment: IEquip.java

  • 2. Implementation classes of each equipment:

  • 3. Superclass of ornaments (ornaments also belong to equipment): IEquipDecorator.java

  • 4. Implementation class of ornaments:

  • 5. Final test: Compute attack power and view description:

    Log.e("---", "A mosaic of 2 rubies,1 Sapphire boots: ");
    IEquip iEquip = new RedGemDecotator(new RedGemDecotator(new BlueGemDecotator(new ShoeEquip())));
    Log.e("---", "Aggressivity:" + iEquip.caculateAttack());
    Log.e("---", "Description:" + iEquip.description());
    

8. Appearance Mode

Definition: Provides a unified interface for accessing a group of interfaces in a subsystem. The appearance defines a high-level interface to make the subsystem easier to use.In fact, to facilitate the use of customers, a group of operations, encapsulated into a method.

  • Demand: I prefer to watch movies, so I bought a projector, computer, audio, designed room lights, bought a popcorn machine, and then when I want to see a movie, I need one click to see it and one click to turn it off.

  • Switching and other operations for each device class:

  • eg: Popcorn maker: PopcornPopper.java

  • Cinema category: HomeTheaterFacade.java

    /**
     * One-click Viewing
     */
    public void watchMovie() {
        computer.on();
        light.down();
        popcornPopper.on();
        popcornPopper.makePopcorn();
        projector.on();
        projector.open();
        player.on();
        player.make3DListener();
    }
    
  • Last test: One-click viewing:

    new HomeTheaterFacade(computer, light, player, popcornPopper, projector).watchMovie();
    

9. Template Method Mode

Definition: Defines the framework of an algorithm, delays some steps to subclasses, and the template method allows subclasses to redefine the steps of the algorithm without changing the structure of the algorithm.

  • Requirements: A brief description: The company has program apes, testing, HR, project managers, etc., below uses the template method mode to record the work of all personnel

  • Three types of roles in the template method pattern

  • 1. Concrete Method

  • 2. Abstract Method

  • 3. Hook Method

  • Superclass of workers: Worker.java

    // Specific methods
    public final void workOneDay() {
        Log.e("workOneDay", "-----------------work start----------------");
        enterCompany();
        work();
        exitCompany();
        Log.e("workOneDay", "-----------------work end----------------");
    }
    // Working abstraction methods
    public abstract void work();
    // Hook Method
    public boolean isNeedPrintDate() {
        return false;
    }
    private void exitCompany() {
        if (isNeedPrintDate()) {
            Log.e("exitCompany", "---" + new Date().toLocaleString() + "--->");
        }
        Log.e("exitCompany", name + "---Leave the company");
    }
    
  • Programmers implement classes (know the time): ITWorker.java

    /**
     * Override this method of the parent class so that you can see the departure time
     */
    @Override
    public boolean isNeedPrintDate() {
        return true;
    }
    
  • Last test:

    • View the work of all people:

      QAWorker qaWorker = new QAWorker("Tester");
      qaWorker();
      HRWorker hrWorker = new HRWorker("Sister Lily");
      hrWorker.workOneDay();
      ...
      
    • See when the ape left the company:

      ITWorker itWorker = new ITWorker("jingbin");
      itWorker.workOneDay();
      

10. State Mode

Definition: Allows an object to change its behavior when its internal state changes, as if the object had modified its class.

  • The definition is blurred again, so when an object's internal state changes, its behavior changes with the change of state, which seems to reinitialize a similar one.

  • Requirements: vending machine as an example (with coined, non-coined status and coined, coined, etc.)

  • Initial implementation of vending machines to be improved: VendingMachine.java

  • Improved vending machine (more scalable): VendingMachineBetter.java

    // Deposit money
    public void insertMoney() {
        currentState.insertMoney();
    }
    // Return money
    public void backMoney() {
        currentState.backMoney();
    }
    // Rotate Crank
    public void turnCrank() {
        currentState.turnCrank();
        if (currentState == soldState || currentState == winnerState) {
            currentState.dispense();//Two cases will ship
        }
    }
    // Export Goods
    public void dispense() {
        Log.e("VendingMachineBetter", "---Send out a commodity");
        if (count > 0) {
            count--;
        }
    }
    // Set corresponding state
    public void setState(State state) {
        this.currentState = state;
    }
    
  • State interface: State.java

  • Interface implementation classes for corresponding states:

  • Improved vending machine test:

    // Initialize the vending machine with 3 items in it
    VendingMachineBetter machineBetter = new VendingMachineBetter(3);
    machineBetter.insertMoney();
    machineBetter.turnCrank();
    

11. Builder Mode

Construction mode is the creative mode of the object.The construction mode can separate the internal representation of a product from the production process of the product, thus enabling a construction process to produce product objects with different internal representations.

  • Requirements: Users go to the car store to buy a car.

  • Analysis: Car stores extract cars based on each user's needs

  • Builder superclass: Builder

    public abstract class Builder {
    
        public abstract void setPart(String name, String type);
    
        public abstract Product getProduct();
    }
    
  • Builder corresponding implementation class: ConcreteBuilder

    public class ConcreteBuilder extends Builder {
    
        private Product product = new Product();
    
        @Override
        public void setPart(String name, String type) {
            product.setName(name);
            product.setType(type);
        }
    
        @Override
        public Product getProduct() {
            return product;
        }
    }
    
  • Shopowner Director Take Car:

    // Shopowner
    Director director = new Director();
    // Get a BMW car, internal implementation of extracting BMW car details
    Product product = director.getBProduct();
    // Show car information
    product.showProduct();
    

12. Prototype mode

Prototype mode is used to create duplicate objects while maintaining performance.This type of design pattern is creative and provides the best way to create objects.

This pattern implements a prototype interface for creating a clone of the current object.This pattern is used when creating objects directly is expensive.For example, an object needs to be created after a costly database operation.We can reduce database calls by caching the object, returning its clone on the next request, and updating the database as needed.

There are four steps to get multiple shapes, for example:

  • 1. Create an abstract class that implements the Cloneable interface. Shape(implements Cloneable)

    public abstract class Shape implements Cloneable {
    
        private String id;
        protected String type;
    
        public abstract void draw();
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        @Override
        public Object clone() {
            Object object = null;
            try {
                object = super.clone();
            } catch (CloneNotSupportedException e) {
                Log.e("--", e.getMessage());
            }
            return object;
        }
    }
    
  • 2. Create entity classes that extend the abstract classes above. Circle,Rectangle,Square

    public class Circle extends Shape {
    
        public Circle() {
            type = "Circle";
        }
    
        @Override
        public void draw() {
            Log.e("---", "Inside Circle::draw() method.");
        }
        
    }
    
  • 3. Create a class, get entity classes from the database, and store them in a Hashtable. ShapeCache

    public class ShapeCache {
    
        private static Hashtable<String, Shape> shapeMap = new Hashtable<String, Shape>();
    
        public static Shape getShape(String shapeId) {
            Shape shapeCache = shapeMap.get(shapeId);
            return (Shape) shapeCache.clone();
        }
    
        // Run a database query on each shape and create it
        // shapeMap.put(shapeKey, shape);
        // For example, we want to add three shapes
        public static void loadCache() {
            Circle circle = new Circle();
            circle.setId("1");
            shapeMap.put(circle.getId(), circle);
    
            Rectangle rectangle = new Rectangle();
            rectangle.setId("2");
            shapeMap.put(rectangle.getId(), rectangle);
    
            Square square = new Square();
            square.setId("3");
            shapeMap.put(square.getId(), square);
        }
    }
    
  • 4. Use the ShapeCache class to obtain clones of shapes stored in Hashtable.

    // Use the ShapeCache class to get a clone of the shape stored in Hashtable.
    ShapeCache.loadCache();
    Shape shapeCache1 = ShapeCache.getShape("1");
    Shape shapeCache2 = ShapeCache.getShape("2");
    Shape shapeCache3 = ShapeCache.getShape("3");
    

13. Enjoyment mode

Mainly used to reduce the number of objects created to reduce memory consumption and improve performance.This type of design pattern is structured and provides a way to reduce the number of objects and improve the object structure required for application.

The enjoyment mode attempts to reuse an existing object of the same type, and if no matching object is found, a new object is created.We'll demonstrate this pattern by creating five objects to draw 20 circles distributed in different locations.Since only five colors are available, the color attribute is used to examine existing Circle objects.

  • The main solution: When there are a large number of objects, memory overflow may occur. We abstract the common parts of them, and if there is the same business request, return the objects that already exist in memory directly to avoid re-creation.

Take random shape acquisition as an example, which is divided into four steps:

  • 1. Create an interface.

    public interface Shape {
        void draw();
    }
    
  • 2. Create entity classes that implement interfaces.

    public class Circle implements Shape {
    
        private String color;
        private int x;
        private int y;
        private int radius;
    
        public Circle(String color) {
            this.color = color;
        }
    
        public void setX(int x) {
            this.x = x;
        }
    
        public void setY(int y) {
            this.y = y;
        }
    
        public void setRadius(int radius) {
            this.radius = radius;
        }
    
        @Override
        public void draw() {
            Log.e("---", "Circle: Draw() [Color : " + color
                    + ", x : " + x + ", y :" + y + ", radius :" + radius);
        }
    }
    
  • 3. Create a factory to generate objects of an entity class based on the given information.

    public class ShapeFactory {
    
        private static final HashMap<String, Shape> circleMap = new HashMap<String, Shape>();
    
        public static Shape getShape(String color) {
            Shape shape = circleMap.get(color);
            if (shape == null) {
                shape = new Circle(color);
                circleMap.put(color, shape);
                Log.e("getShape", "Creating circle of color : " + color);
            }
            return shape;
        }
    
    }
    
  • 4. Use the factory to get objects of entity class by passing color information.

    for (int i = 0; i < 20; i++) {
        Circle circle = (Circle) ShapeFactory.getShape(getRandomColor());
        circle.setX(getRandomX());
        circle.setY(getRandomY());
        circle.setRadius(100);
        circle.draw();
    }
    

14. Agent mode

One class represents the functionality of another class.In proxy mode, we create objects with existing objects to provide functional interfaces to the outside world.It can be understood that an object is created without it in memory and returned directly if it exists.

  • Main Solution: Problems caused by direct access to objects, such as: the object to be accessed is on a remote machine.In an object-oriented system, direct access to some objects can cause a lot of trouble to users or the system structure for some reasons, such as the overhead of object creation, the need for security control for some operations, or the need for out-of-process access. We can add an access layer to this object when accessing it.

For example, there are three steps to getting pictures from disk:

  • 1. Create an interface.

    public interface Image {
       void display();
    }
    
  • 2. Create the entity class RealImage that implements the interface.Corresponding proxy class: ProxyImage.

    public class RealImage implements Image {
    
        private String fileName;
    
        public RealImage(String fileName) {
            this.fileName = fileName;
            loadFromDisk(fileName);
        }
    
        private void loadFromDisk(String fileName) {
            Log.e("RealImage", "loading " + fileName);
        }
    
        @Override
        public void display() {
            Log.e("RealImage", "Displaying " + fileName);
        }
    }
    
    public class ProxyImage implements Image {
    
        private String fileName;
        private RealImage realImage;
    
        public ProxyImage(String fileName) {
            this.fileName = fileName;
        }
    
        @Override
        public void display() {
            if (realImage == null) {
                realImage = new RealImage(fileName);
            }
            realImage.display();
        }
    }
    
  • 3. Use ProxyImage to get objects of RealImage class when requested.

    Image image = new ProxyImage("test_10mb.png");
    // The first time was new, the image was loaded from disk
    image.display();
    // The second time the cache is fetched, the image does not need to be loaded from disk
    image.display();
    

15. Bridge mode

Bridge is used to decouple abstraction from implementation so that they can change independently.This type of design pattern is a structural one, which decouples abstraction from realisation by providing a bridge between them.

  • Main Solution: Inheritance can cause class explosion and is not flexible to expand in a variety of possible situations.

Take drawing circles of different colors as an example, the implementation is divided into five steps:

  • 1. Create bridges to implement interfaces.

    public interface DrawAPI {
        void drawCircle(int radius, int x, int y);
    }
    
  • 2. Create an entity bridge implementation class that implements the DrawAPI interface. RedCircle,GreenCircle

    public class RedCircle implements DrawAPI {
    
        @Override
        public void drawCircle(int radius, int x, int y) {
            Log.e("---", "Drawing Circle[ color: red, radius: "
                    + radius + ", x: " + x + ", " + y + "]");
        }
    }
    
  • 3. Create abstract classes using DrawAPI interface Shape.

    public abstract class Shape {
    
        protected DrawAPI drawAPI;
    
        protected Shape(DrawAPI drawAPI) {
            this.drawAPI = drawAPI;
        }
    
        public abstract void draw();
    }
    
  • 4. Create an entity class that implements the Shape interface.

    public class Circle extends Shape {
    
        private int x, y, radius;
    
        protected Circle(int x, int y, int radius, DrawAPI drawAPI) {
            super(drawAPI);
            this.x = x;
            this.y = y;
            this.radius = radius;
        }
    
        @Override
        public void draw() {
            drawAPI.drawCircle(radius, x, y);
        }
    }
    
  • 5. Draw different colored circles using Shape and DrawAPI classes.

    // Draw a red circle
    Circle circle = new Circle(10, 10, 100, new RedCircle());s
    circle.draw();
    // Draw a green circle
    Circle circle2 = new Circle(20, 20, 100, new GreenCircle());
    circle2.draw();
    

16. Combination mode

Also known as partial holistic mode, it is used to treat a group of similar objects as a single object.Combination modes combine objects based on a tree structure to represent parts as well as the overall hierarchy.This type of design pattern is structured, creating a tree structure of object groups.

  • Main Solution: It blurs the concepts of simple and complex elements in our tree structure. Client programs can handle complex elements like simple elements, thus decoupling the internal structure of complex elements from client programs.

Take the example of creating and printing a hierarchy of employees, the minimum unit example:

  • 1. Create an Employee class with a list of Employee objects.

    public class Employee {
    
        private String name;
        // department
        private String dept;
        // wages
        private int salary;
        // Employee list
        private List<Employee> subordinates;
    
        public Employee(String name, String dept, int salary) {
            this.name = name;
            this.dept = dept;
            this.salary = salary;
            this.subordinates = new ArrayList<Employee>();
        }
    
        public void add(Employee e) {
            subordinates.add(e);
        }
    
        public void remove(Employee e) {
            subordinates.remove(e);
        }
    
        public List<Employee> getSubordinates() {
            return subordinates;
        }
    
        @Override
        public String toString() {
            return "Employee{" +
                    "name='" + name + '\'' +
                    ", dept='" + dept + '\'' +
                    ", salary=" + salary +
                    ", subordinates=" + subordinates +
                    '}';
        }
    }
    
  • 2. Use the Employee class to create and print a hierarchy of employees.

    final Employee ceo = new Employee("John", "CEO", 30000);
    
    Employee headSales = new Employee("Robert", "Head sales", 20000);
    
    Employee headMarketing = new Employee("Michel", "Head Marketing", 20000);
    
    Employee clerk1 = new Employee("Laura", "Marketing", 10000);
    Employee clerk2 = new Employee("Bob", "Marketing", 10000);
    
    Employee salesExecutive1 = new Employee("Richard", "Sales", 10000);
    Employee salesExecutive2 = new Employee("Rob", "Sales", 10000);
    
    ceo.add(headSales);
    ceo.add(headMarketing);
    
    headSales.add(salesExecutive1);
    headSales.add(salesExecutive2);
    
    headMarketing.add(clerk1);
    headMarketing.add(clerk2);
    
    Log.e("---", ceo.toString());
    
    // Print
    /*
     * Employee{name='John', dept='CEO', salary=30000,
     * subordinates=[Employee{name='Robert', dept='Head sales', salary=20000,
     * subordinates=[
     * Employee{name='Richard', dept='Sales', salary=10000, subordinates=[]},
     * Employee{name='Rob', dept='Sales', salary=10000, subordinates=[]}]},
     * Employee{name='Michel', dept='Head Marketing', salary=20000,
     * subordinates=[Employee{name='Laura', dept='Marketing', salary=10000, subordinates=[]},
     * Employee{name='Bob', dept='Marketing', salary=10000, subordinates=[]}]}]}
     */
    

17. Iterator mode

Design patterns that are very common in Java and.Net programming environments.This pattern is used to sequentially access the elements of a collection object without knowing the underlying representation of the collection object.Iterator mode is behavioral.

  • The main solution is to traverse the entire integrated object in different ways.

For example, using an iterator to print names is a three-step process:

  • 1. Create interfaces:

    public interface Iterator {
    
        public boolean hasNext();
    
        public Object next();
    }
    
    public interface Container {
        public Iterator getIterator();
    }
    
  • 2. Create an entity class that implements the Container interface.This class has an internal class NameIterator that implements the Iterator interface.

    public class NameRepository implements Container {
    
        private String names[] = {"John", "jingbin", "youlookwhat", "lookthis"};
    
        @Override
        public Iterator getIterator() {
            return new NameIterator();
        }
    
        private class NameIterator implements Iterator {
    
            int index;
    
            @Override
            public boolean hasNext() {
                if (index < names.length) {
                    return true;
                }
                return false;
            }
    
            @Override
            public Object next() {
                if (hasNext()) {
                    return names[index++];
                }
                return null;
            }
        }
    
    }
    
  • 3. Use NameRepository to get the iterator and print the name.

    NameRepository nameRepository = new NameRepository();
    for (Iterator iterator = nameRepository.getIterator(); iterator.hasNext(); ) {
        String name = (String) iterator.next();
        Log.e("---", name);
        /*
         * /---: John
         * /---: jingbin
         * /---: youlookwhat
         * /---: lookthis
         */
    }
    

18. Intermediator Model

Used to reduce communication complexity between multiple objects and classes.This pattern provides a mediation class that typically handles communication between different classes, supports loose coupling, and makes code easy to maintain.The intermediary model is behavioral.

  • Main Solution: There are a large number of associations between objects, which will inevitably lead to complex system structure. At the same time, if an object changes, we also need to track the objects associated with it and make corresponding processing.

For example, in a public chat room, the minimum unit example steps are:

  • 1. Create a mediation class.

    public class CharRoom {
        public static void showMessage(User user, String message) {
            Log.e("---", new Date().toString()
                    + " [" + user.getName() + "] : " + message);
        }
    }
    
  • 2. Create user class.

    public class User {
        private String name;
    
        public User(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void sendMessage(String message) {
        	  // Using mediation classes
            CharRoom.showMessage(this, message);
        }
    }
    
  • 3. Use the User object to display the communication between them.

        User jingbin = new User("jingbin");
        jingbin.sendMessage("Hi~ youlookwhat!");
        //---: Sun Feb 02 08:11:47 GMT+00:00 2020 [jingbin] : Hi~ youlookwhat!
        
        User jingbin = new User("youlookwhat");
        jingbin.sendMessage("Hi~ jingbin!");
        //---: Sun Feb 02 08:11:49 GMT+00:00 2020 [youlookwhat] : Hi~ jingbin!
    

19. Memo Mode

Save a state of an object to restore it at the appropriate time.The memo mode is behavioral.

  • Main Solution: The so-called memo mode is to capture the internal state of an object without destroying the encapsulation and save the state outside the object so that the object can be restored to its original state in the future.

Using a memo as an example, the minimum unit step is:

  • 1. Create a memo Memento class.

    public class Memento {
    
    	private String state;
    	
    	public Memento(String state) {
    	    this.state = state;
    	}
    	
    	public String getState() {
    	    return state;
    	}
    	
    	public void setState(String state) {
    	    this.state = state;
    	}
    }
    
  • 2. Create Originator class.

    public class Originator {
    
        private String state;
    
        public String getState() {
            return state;
        }
    
        public void setState(String state) {
            this.state = state;
        }
    
        public Memento setSateToMemento() {
            return new Memento(state);
        }
    
        public String getStateFromMemento(Memento memento) {
            return memento.getState();
        }
    }
    
  • 3. Create CareTaker class.

    public class CareTaker {
    
        private List<Memento> mementoList = new ArrayList<Memento>();
    
        public void add(Memento memento) {
            mementoList.add(memento);
        }
    
        public Memento get(int index) {
            return mementoList.get(index);
        }
    }
    
  • 4. Use CareTaker and Originator objects.

    // Controller
    CareTaker careTaker = new CareTaker();
    
    Originator originator = new Originator();
    originator.setState("State #1");
    originator.setState("State #2");
    
    // Save State
    careTaker.add(originator.setSateToMemento());
    
    originator.setState("State #3");
    
    // Save State
    careTaker.add(originator.setSateToMemento());
    
    originator.setState("State #4");
    
    Log.e("---", "Current State: " + originator.getState());
    // Saved state
    String fromMemento1 = originator.getStateFromMemento(careTaker.get(0));
    Log.e("---", "First Saved State: " + fromMemento1);
    String fromMemento2 = originator.getStateFromMemento(careTaker.get(1));
    Log.e("---", "Second Saved State: " + fromMemento2);
    
    /*
     * /---: Current State: State #4
     * /---: First Saved State: State #2
     * /---: Second Saved State: State #3
     */
    

20. Interpreter mode

Provides a way to evaluate the grammar or expression of a language, which is behavioral.This pattern implements an expression interface that interprets a specific context.This pattern is used in SQL parsing, symbol processing engines, and so on.

  • The main solution is to construct an interpreter to interpret sentences for some fixed grammars.

To illustrate a sentence, for example, the minimum unit step is:

  • 1. Create an expression interface Expression.

    public interface Expression {
        public boolean interpreter(String content);
    }
    
  • 2. Create entity classes that implement the above interfaces.TerminalExpression, OrExpression, AndExpression.

    public class TerminalExpression implements Expression {
    
    	private String data;
    	
    	public TerminalExpression(String data) {
    	    this.data = data;
    	}
    	
    	@Override
    	public boolean interpreter(String content) {
    	   // Is Inclusive Judgment
    	    return content.contains(data);
    	}
    }
    
    public class OrExpression implements Expression {
    
        private Expression expression1;
        private Expression expression2;
    
        public OrExpression(Expression expression1, Expression expression2) {
            this.expression1 = expression1;
            this.expression2 = expression2;
        }
    
        @Override
        public boolean interpreter(String content) {
            return expression1.interpreter(content) || expression2.interpreter(content);
        }
    }
    
    public class AndExpression implements Expression {
    
        private Expression expression1;
        private Expression expression2;
    
        public AndExpression(Expression expression1, Expression expression2) {
            this.expression1 = expression1;
            this.expression2 = expression2;
        }
    
        @Override
        public boolean interpreter(String content) {
            return expression1.interpreter(content) && expression2.interpreter(content);
        }
    }
    
  • 3. Use the Expression class to create rules and parse them.

    /**
     * Rule: jingbin and youlookwhat are men
     */
    public static Expression getMaleExpression() {
        TerminalExpression jingbin = new TerminalExpression("jingbin");
        TerminalExpression youlookwhat = new TerminalExpression("youlookwhat");
        return new OrExpression(jingbin, youlookwhat);
    }
    
    /**
     * Rule: Julie is a married woman
     */
    public static Expression getMarriedWomanExpression() {
        TerminalExpression julie = new TerminalExpression("Julie");
        TerminalExpression married = new TerminalExpression("Married");
        return new AndExpression(julie, married);
    }
    
    Expression maleExpression = getMaleExpression();
    // jingbin is male: true
    Log.e("---", "jingbin is male: " + maleExpression.interpreter("jingbin"));
    
    Expression womanExpression = getMarriedWomanExpression();
    // Julie is married woman: true
    Log.e("---", "Julie is married woman: " + womanExpression.interpreter("Married Julie"));
    
    

21. Responsibility Chain Model

Chain of Responsibility Pattern creates a chain of recipient objects for a request.This pattern gives the type of request and decouples the sender and receiver of the request.This type of design pattern is behavioral.In this mode, each recipient usually contains a reference to another recipient.If an object cannot process the request, it will pass the same request to the next recipient, and so on.

  • Main Solution: The handler in the responsibility chain handles the request. The client only needs to send the request to the responsibility chain, and does not need to care about the details of the request processing and the transfer of the request, so the responsibility chain decouples the sender of the request from the handler of the request.

Take the example of printing logs in Android Studio, the minimum unit step:

  • 1. Create an abstract recorder class, AbstractLogger.

    public abstract class AbstractLogger {
    
        public static int INFO = 1;
        public static int DEBUG = 2;
        public static int ERROR = 3;
    
        protected int level;
    
        // Next element in the chain of responsibility
        protected AbstractLogger nextLogger;
    
        public void setNextLogger(AbstractLogger nextLogger) {
            this.nextLogger = nextLogger;
        }
    
        public void logMessage(int level, String message) {
            if (this.level <= level) {
                write(message);
            }
            // Recursive effect, constantly calling the next level of logMessage
            if (nextLogger != null) {
                nextLogger.logMessage(level, message);
            }
        }
    
        protected abstract void write(String message);
    }
    
  • 2. Create an entity class that extends the recorder class.

    public class ConsoleLogger extends AbstractLogger {
    
        public ConsoleLogger(int level) {
            this.level = level;
        }
    
        @Override
        protected void write(String message) {
            Log.e("---", "Standard Console::Logger  " + message);
        }
    }
    
    public class FileLogger extends AbstractLogger {
    
        public FileLogger(int level) {
            this.level = level;
        }
    
        @Override
        protected void write(String message) {
            Log.e("---", "File::Logger  " + message);
        }
    }
    
    public class ErrorLogger extends AbstractLogger {
    
        public ErrorLogger(int level) {
            this.level = level;
        }
    
        @Override
        protected void write(String message) {
            Log.e("---", "Error Console::Logger  " + message);
        }
    }
    
  • 3. Create different types of recorders.Give them different error levels and set the next recorder in each recorder.The next recorder in each recorder represents a part of the chain.

    public static AbstractLogger getChainOfLoggers() {
        ErrorLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);
        FileLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);
        ConsoleLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);
        errorLogger.setNextLogger(fileLogger);
        fileLogger.setNextLogger(consoleLogger);
        return errorLogger;
    }
    
    AbstractLogger logger = getChainOfLoggers();
    
    // ---: Standard Console::Logger  this is an information.
    logger.logMessage(AbstractLogger.INFO, "this is an information.");
    
    // ---: File::Logger  this is a debug level information.
    // ---: Standard Console::Logger  this is a debug level information.
    logger.logMessage(AbstractLogger.DEBUG, "this is a debug level information.");
    
    // ---: Error Console::Logger  this is a error level information.
    // ---: File::Logger  this is a error level information.
    // ---: Standard Console::Logger  this is a error level information.
    logger.logMessage(AbstractLogger.ERROR, "this is a error level information.");
    
    

22. Visitor Mode

In Visitor Mode, we use a Visitor class that changes the execution algorithm for element classes.In this way, the element's execution algorithm can change as the visitor changes.This type of design pattern is behavioral.Depending on the schema, the element object already accepts a visitor object so that the visitor object can handle operations on the element object.

  • The main solutions are: stable data structure and variable operation coupling.

In the case of displaying the components of a computer, there are five main steps:

  • 1. Define an interface that represents an element.

    public interface ComputerPart {
        public void accept(ComputerPartVisitor computerPartVisitor);
    }
    
  • 2. Create entity classes that extend the above classes. Keyboard,Monitor,Mouse,Computer

    public class Computer implements ComputerPart {
    
        private ComputerPart[] parts;
    
        public Computer() {
            this.parts = new ComputerPart[]{new Mouse(), new Keyboard(), new Monitor()};
        }
    
        @Override
        public void accept(ComputerPartVisitor computerPartVisitor) {
            for (ComputerPart part : parts) {
                part.accept(computerPartVisitor);
            }
            computerPartVisitor.visit(this);
        }
    }
    
    public class Mouse implements ComputerPart {
        @Override
        public void accept(ComputerPartVisitor computerPartVisitor) {
            computerPartVisitor.visit(this);
        }
    }
    
  • 3. Define an interface that represents the visitor.

    public interface ComputerPartVisitor {
    
        public void visit(Computer computer);
    
        public void visit(Mouse mouse);
    
        public void visit(Keyboard keyboard);
    
        public void visit(Monitor monitor);
    }
    
  • 4. Create entity visitors that implement the above classes.

    public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
    
        @Override
        public void visit(Computer computer) {
            Log.e("---", "Displaying Computer.");
        }
    
        @Override
        public void visit(Mouse mouse) {
            Log.e("---", "Displaying Mouse.");
        }
    
        @Override
        public void visit(Keyboard keyboard) {
            Log.e("---", "Displaying Keyboard.");
        }
    
        @Override
        public void visit(Monitor monitor) {
            Log.e("---", "Displaying Monitor.");
        }
    }
    
  • 5. Use ComputerPartDisplayVisitor to display the components of Computer.

        ComputerPart computer = new Computer();
        computer.accept(new ComputerPartDisplayVisitor());
        /*
         *Print:
         *---: Displaying Mouse.
         *---: Displaying Keyboard.
         *---: Displaying Monitor.
         *---: Displaying Computer.
         */
    

Download

Reference

About me

87 original articles were published. 47 were praised. 100,000 visits+
Private letter follow

Topics: Java Mobile Database github