An infinite menu tree without performance bottlenecks should be designed like this

This article is excerpted from "design patterns should be learned this way"

1. Use transparent combination mode to realize course directory structure

Taking an online course as an example, we design the relationship structure of a course. For example, we have introductory Java courses, artificial intelligence courses, Java design patterns, source code analysis, soft skills, etc., while Java design patterns, source code analysis and soft skills belong to the Java Architect Series of course packages, and the pricing of each course is different. However, no matter how these courses are combined, they have some commonalities, and they are the relationship between the whole and part, which can be designed with the combination mode. First, create a top-level abstract component CourseComponent class.

/**
 * Created by Tom.
 */
public abstract class CourseComponent {

    public void addChild(CourseComponent catalogComponent){
        throw new UnsupportedOperationException("Add operation is not supported");
    }

    public void removeChild(CourseComponent catalogComponent){
        throw new UnsupportedOperationException("Delete operation is not supported");
    }


    public String getName(CourseComponent catalogComponent){
        throw new UnsupportedOperationException("Get name operation is not supported");
    }


    public double getPrice(CourseComponent catalogComponent){
        throw new UnsupportedOperationException("Get price operation is not supported");
    }


    public void print(){
        throw new UnsupportedOperationException("Printing is not supported");
    }

}

Define all possible methods into the top-level abstract component, but do not write any logic processing code, but directly throw exceptions. Here, some little friends will wonder, why not use abstract methods? Because the abstract method is used, its subclasses must be implemented, so that the subtle differences between subclasses cannot be reflected. Therefore, after the subclass inherits this abstract class, it only needs to override the different methods to override the methods of the parent class.
Then create Course class and Course package CoursePackage class respectively. The code to create the Course class is as follows.

/**
 * Created by Tom.
 */
public class Course extends CourseComponent {
    private String name;
    private double price;

    public Course(String name, double price) {
        this.name = name;
        this.price = price;
    }

    @Override
    public String getName(CourseComponent catalogComponent) {
        return this.name;
    }

    @Override
    public double getPrice(CourseComponent catalogComponent) {
        return this.price;
    }

    @Override
    public void print() {
        System.out.println(name + " (¥" + price + "element)");
    }

}

The code to create the CoursePackage class is as follows.

/**
 * Created by Tom.
 */
public class CoursePackage extends CourseComponent {
    private List<CourseComponent> items = new ArrayList<CourseComponent>();
    private String name;
    private Integer level;


    public CoursePackage(String name, Integer level) {
        this.name = name;
        this.level = level;
    }

    @Override
    public void addChild(CourseComponent catalogComponent) {
        items.add(catalogComponent);
    }

    @Override
    public String getName(CourseComponent catalogComponent) {
        return this.name;
    }

    @Override
    public void removeChild(CourseComponent catalogComponent) {
        items.remove(catalogComponent);
    }

    @Override
    public void print() {
        System.out.println(this.name);

        for(CourseComponent catalogComponent : items){
            //Control display format
            if(this.level != null){
                for(int  i = 0; i < this.level; i ++){
                    //Print space control format
                    System.out.print("  ");
                }
                for(int  i = 0; i < this.level; i ++){
                    //Print a + sign at the beginning of each line
                    if(i == 0){ System.out.print("+"); }
                    System.out.print("-");
                }
            }
            //Print title
            catalogComponent.print();
        }
    }

}

Finally, write the client test code.

public static void main(String[] args) {

        System.out.println("============Transparent combination mode===========");

        CourseComponent javaBase = new Course("Java introductory course ",8280);
        CourseComponent ai = new Course("artificial intelligence",5000);

        CourseComponent packageCourse = new CoursePackage("Java Architect course",2);

        CourseComponent design = new Course("Java Design pattern",1500);
        CourseComponent source = new Course("Source code analysis",2000);
        CourseComponent softSkill = new Course("Soft skills",3000);

        packageCourse.addChild(design);
        packageCourse.addChild(source);
        packageCourse.addChild(softSkill);

        CourseComponent catalog = new CoursePackage("Course home directory",1);
        catalog.addChild(javaBase);
        catalog.addChild(ai);
        catalog.addChild(packageCourse);

        catalog.print();

}

The operation results are shown in the figure below.

The transparent composition mode defines all public methods in the Component, so that the client does not need to distinguish whether the operation object is a leaf node or a branch node; However, the leaf node inherits some methods that it does not need (methods to manage subclass operations), which is contrary to the interface isolation principle of design pattern.

2. Use secure combination mode to realize infinite file system

Take another example that programmers are more familiar with. For programmers, computers are exposed every day. The computer file system is actually a typical tree structure. The directory contains folders and files, and the folder can contain folders and files. The following code is used to implement a directory system.
The file system has two levels: folders and files. Among them, the folder can accommodate other levels and is a branch node; The file is the smallest unit and is the leaf node. Because the Directory system has few levels and the tree node (folder) structure is relatively stable, and there can be many types of files, we choose to use the safe combination mode to implement the Directory system, which can avoid introducing redundancy methods for leaf node types (files). First, create the top-level abstract component Directory class.

public abstract class Directory {

    protected String name;

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

    public abstract void show();

}

Then create File class and Folder class respectively. The code to create the File class is as follows.

public class File extends Directory {

    public File(String name) {
        super(name);
    }

    @Override
    public void show() {
        System.out.println(this.name);
    }

}

The code to create the Folder class is as follows.

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

public class Folder extends Directory {
    private List<Directory> dirs;

    private Integer level;

    public Folder(String name,Integer level) {
        super(name);
        this.level = level;
        this.dirs = new ArrayList<Directory>();
    }

    @Override
    public void show() {
        System.out.println(this.name);
        for (Directory dir : this.dirs) {
            //Control display format
            if(this.level != null){
                for(int  i = 0; i < this.level; i ++){
                    //Print space control format
                    System.out.print("  ");
                }
                for(int  i = 0; i < this.level; i ++){
                    //Print a + sign at the beginning of each line
                    if(i == 0){ System.out.print("+"); }
                    System.out.print("-");
                }
            }
            //Print name
            dir.show();
        }
    }

    public boolean add(Directory dir) {
        return this.dirs.add(dir);
    }

    public boolean remove(Directory dir) {
        return this.dirs.remove(dir);
    }

    public Directory get(int index) {
        return this.dirs.get(index);
    }

    public void list(){
        for (Directory dir : this.dirs) {
            System.out.println(dir.name);
        }
    }

}

Note that the Folder class not only covers the show() method at the top level, but also adds the list() method.
Finally, write the client test code.

    public static void main(String[] args) {

        System.out.println("============Safe combination mode===========");

        File qq = new File("QQ.exe");
        File wx = new File("WeChat.exe");

        Folder office = new Folder("Office software",2);

        File word = new File("Word.exe");
        File ppt = new File("PowerPoint.exe");
        File excel = new File("Excel.exe");

        office.add(word);
        office.add(ppt);
        office.add(excel);

        Folder wps = new Folder("Jinshan Software",3);
        wps.add(new File("WPS.exe"));
        office.add(wps);

        Folder root = new Folder("root directory",1);
        root.add(qq);
        root.add(wx);
        root.add(office);

        System.out.println("----------show()Method effect-----------");
        root.show();

        System.out.println("----------list()Method effect-----------");
        root.list();

}

The operation results are shown in the figure below.

The advantage of security combination mode is that the interface definition responsibility is clear, which conforms to the single responsibility principle and interface isolation principle of design mode; The disadvantage is that customers need to distinguish between branch nodes and leaf nodes in order to correctly handle operations at all levels. The client cannot rely on abstract interfaces (components), which violates the dependency inversion principle of design patterns.

[recommendation] Tom bomb architecture: collecting this article is equivalent to collecting a book on "design patterns"

This article is the original of "Tom bomb architecture". Please indicate the source for reprint. Technology lies in sharing, I share my happiness!
If this article is helpful to you, you are welcome to pay attention and praise; If you have any suggestions, you can also leave comments or private letters. Your support is the driving force for me to adhere to my creation. Focus on WeChat official account Tom structure, get more dry cargo!

Tags: Java Design Pattern architecture

Posted on Thu, 04 Nov 2021 05:38:56 -0400 by Lambneck