编程知识 cdmana.com

Design pattern -- composite pattern

Cited example

Before we introduce it, let's look at an example , It's about the company's personnel management system :

This is a typical tree structure , So how can we code it ?

analysis :

There are two different kinds of nodes :

  • Nodes with branches :
    • The root node : The general manager
    • The branch node : R & D Manager
  • Nodes without branches :
    • Leaf node : Developer

That's to say. , Just define three classes , Here's the picture :

Let's implement the code according to this class diagram :

First of all Root node interface

/**
 *  Root node interface 
 *
 * @author wang suo
 * @version 1.0
 * @date 2020/12/21 0021 22:36
 */
public interface IRoot {
    /**
     *  Get information from the general manager 
     *
     * @return  Return information 
     */
    String getInfo();

    /**
     *  There should be soldiers under the general manager - To be able to increase the number of soldiers - For example, R & D managers - This is the branch node 
     *
     * @param iBranch  Nodes with branches 
     */
    void add(IBranch iBranch);

    /**
     *  How to add leaf nodes 
     *
     * @param iLeaf  Leaf node 
     */
    void add(ILeaf iLeaf);

    /**
     *  And be able to traverse - No way. The general manager doesn't know how many people he's taking in 
     *
     * @return  Back to all of your men [ aggregate ]
     */
    List getSubordinateInfo();
}

Of the root node interface Implementation class , It's our general manager here :

/**
 *  The implementation class of the root node 
 *
 * @Author wang suo
 * @Date 2020/12/22 0022 11:03
 * @Version 1.0
 */
public class Root implements IRoot {
    /**
     *  Save all the branch nodes and leaf nodes under the root node 
     */
    private List<Object> subordinateList = new ArrayList<>();

    /**
     *  The name of the root node 
     */
    private String name = "";

    /**
     *  The root node of the position 
     */
    private String position = "";

    /**
     *  The salary of the root node 
     */
    private int salary = 0;

    public Root(String name, String position, int salary) {
        this.name = name;
        this.position = position;
        this.salary = salary;
    }

    @Override
    public String getInfo() {
        String info = "";
        info = " name : " + this.name;
        info = info + "\t Position : " + this.position;
        info = info + "\t salary : " + this.salary;
        return info;
    }

    /**
     *  Add leaf nodes 
     *
     * @param iBranch  Nodes with branches 
     */
    @Override
    public void add(IBranch iBranch) {
        subordinateList.add(iBranch);
    }

    /**
     *  Add leaf nodes - It belongs directly to the general manager - Like secretaries 
     *
     * @param iLeaf  Leaf node 
     */
    @Override
    public void add(ILeaf iLeaf) {
        subordinateList.add(iLeaf);
    }

    @Override
    public List getSubordinateInfo() {
        return this.subordinateList;
    }
}

Nodes with branches Interface :

/**
 *  Node interfaces with branches 
 *
 * @author wang suo
 * @version 1.0
 * @date 2020/12/21 0021 22:38
 */
public interface IBranch {
    /**
     *  Get your own information 
     *
     * @return  Return information 
     */
    String getInfo();

    /**
     *  Add data nodes - For example, the R & D team under the R & D department 
     *
     * @param iBranch  Nodes with branches 
     */
    void add(IBranch iBranch);

    /**
     *  How to add leaf nodes 
     *
     * @param iLeaf  Leaf node 
     */
    void add(ILeaf iLeaf);

    /**
     *  Get information from below 
     *
     * @return  Back to all of your men [ aggregate ]
     */
    List getSubordinateInfo();
}

Node implementation with branches :

/**
 *  The node implementation of the branch 
 *
 * @Author wang suo
 * @Date 2020/12/22 0022 11:16
 * @Version 1.0
 */
public class Branch implements IBranch {
    /**
     *  Store information about child nodes 
     */
    private List<Object> subordinateList = new ArrayList<>();

    private String name = "";

    private String position = "";

    private int salary = 0;

    public Branch(String name, String position, int salary) {
        this.name = name;
        this.position = position;
        this.salary = salary;
    }

    @Override
    public String getInfo() {
        String info = "";
        info = " name : " + this.name;
        info = info + "\t Position : " + this.position;
        info = info + "\t salary : " + this.salary;
        return info;
    }

    @Override
    public void add(IBranch iBranch) {
        this.subordinateList.add(iBranch);
    }

    @Override
    public void add(ILeaf iLeaf) {
        this.subordinateList.add(iLeaf);
    }

    @Override
    public List getSubordinateInfo() {
        return this.subordinateList;
    }
}

Leaf node The interface of :

/**
 *  The interface of the leaf node 
 *
 * @author wang suo
 * @version 1.0
 * @date 2020/12/21 0021 22:38
 */
public interface ILeaf {
    /**
     *  pick up information 
     *
     * @return  Return information 
     */
    String getInfo();
}

The implementation of leaf node :

/**
 *  The implementation of leaf node 
 *
 * @Author wang suo
 * @Date 2020/12/22 0022 11:20
 * @Version 1.0
 */
public class Leaf implements ILeaf {
    /**
     *  What's the name of the leaf 
      */
    private String name = "";

    /**
     *  Leaf's position 
     */
    private String position = "";

    /**
     *  Leaf's salary 
     */
    private int salary = 0;

    public Leaf(String name, String position, int salary) {
        this.name = name;
        this.position = position;
        this.salary = salary;
    }

    @Override
    public String getInfo() {
        String info = "";
        info = " name : " + this.name;
        info = info + "\t Position : " + this.position;
        info = info + "\t salary : " + this.salary;
        return info;
    }
}

All the root nodes , Both the branch node and the leaf node have been implemented , And then we do it The environment class

/**
 *  Scene class 
 *
 * @Author wang suo
 * @Date 2020/12/22 0022 11:22
 * @Version 1.0
 */
public class Client {
    public static void main(String[] args) {
        //  First, a root node is generated 
        IRoot ceo = new Root(" Wang damazi ", " The general manager ", 100000);
        //  produce  3  Department managers 
        Branch developDep = new Branch(" Big Liu lame ", " R & D Manager ", 10000);
        Branch salesDep = new Branch(" Ma er Guaizi ", " Sales Manager ", 20000);
        Branch financeDep = new Branch(" Zhao santuozi ", " Finance Manager ", 30000);
        //  In the development department 3 A team leader 
        IBranch firstDevGroup = new Branch(" Yang sanmuchi ", " Development team leader ", 5000);
        IBranch secondDevGroup = new Branch(" Wu stick mallet ", " Leader of development group 2 ", 6000);

        //  All that's left is us little soldiers , It's a passer-by , Passers-by b 
        ILeaf a = new Leaf("a", " Developer ", 2000);
        ILeaf b = new Leaf("b", " Developer ", 2000);
        ILeaf c = new Leaf("c", " Developer ", 2000);
        ILeaf d = new Leaf("d", " Developer ", 2000);
        ILeaf e = new Leaf("e", " Developer ", 2000);
        ILeaf f = new Leaf("f", " Developer ", 2000);
        ILeaf g = new Leaf("g", " Developer ", 2000);
        ILeaf h = new Leaf("h", " Salesman ", 5000);
        ILeaf i = new Leaf("i", " Salesman ", 4000);
        ILeaf j = new Leaf("j", " financial staff ", 5000);
        ILeaf k = new Leaf("k", "CEO secretary ", 8000);
        ILeaf zhengLaoLiu = new Leaf(" Zheng Laoliu ", " Vice president of R & D department ", 20000);

        //  All the people who should be born have come out , And then how do we assemble this tree 
        //  The first is to define that there are three department managers under the general manager 
        ceo.add(developDep);
        ceo.add(salesDep);
        ceo.add(financeDep);
        //  There is also a secretary under the general manager 
        ceo.add(k);

        //  Define the structure under the R & D department 
        developDep.add(firstDevGroup);
        developDep.add(secondDevGroup);
        //  There is also a vice president under the R & D manager 
        developDep.add(zhengLaoLiu);

        //  Let's see what's under the two development teams 
        firstDevGroup.add(a);
        firstDevGroup.add(b);
        firstDevGroup.add(c);
        secondDevGroup.add(d);
        secondDevGroup.add(e);
        secondDevGroup.add(f);

        //  Let's look at the personnel in the sales department 
        salesDep.add(h);
        salesDep.add(i);

        // The last Finance 
        financeDep.add(j);

        // The tree structure is finished , And then we print it out 
        System.out.println(ceo.getInfo());

        // Print out the whole tree 
        getAllSubordinateInfo(ceo.getSubordinateInfo());
    }

    /**
     *  Traverse and print the entire tree 
     *
     * @param subordinateList  Tree or subtree 
     */
    private static void getAllSubordinateInfo(List subordinateList) {
        for (Object o : subordinateList) {
            if (o instanceof Leaf) {
                System.out.println(((Leaf) o).getInfo());
            } else {
                IBranch branch = (IBranch) o;
                System.out.println(branch.getInfo());
                //  Recursively call 
                getAllSubordinateInfo(branch.getSubordinateInfo());
            }
        }
    }
}

Execution results :

 name :  Wang damazi 	 Position :  The general manager 			 salary : 100000
 name : k			 Position : CEO secretary 		 salary : 8000
 name :  Big Liu lame 	 Position :  R & D Manager 		 salary : 10000
 name :  Zheng Laoliu 		 Position :  Deputy manager of R & D department 		 salary : 20000
 name :  Yang sanmuchi 	 Position :  Development team leader 		 salary : 5000
 name : a			 Position :  Developer 		 salary : 2000
 name : b			 Position :  Developer 		 salary : 2000
 name : c			 Position :  Developer 		 salary : 2000
 name :  Wu stick mallet 	 Position :  Leader of development group 2 		 salary : 6000
 name : d			 Position :  Developer 		 salary : 2000
 name : e			 Position :  Developer 		 salary : 2000
 name : f			 Position :  Developer 		 salary : 2000
 name :  Ma er Guaizi 	 Position :  Sales Manager 		 salary : 20000
 name : h			 Position :  Salesman 		 salary : 5000
 name : i			 Position :  Salesman 		 salary : 4000
 name :  Zhao santuozi 	 Position :  Finance Manager 		 salary : 30000
 name : j			 Position :  financial staff 		 salary : 5000

The problem is

Now let's analyze the problems in the above code and architecture :

  • We found that Root Classes and Branch Class is almost the same , So these two can be combined ;
  • In addition, every node has getInfo Method , So we can extract an abstract class ;

The modified class diagram

The simplified code is very concise , And environment classes only need direct and abstract classes Corp It's OK to relate , The code is as follows :

abstract Company staff

/**
 *  Abstract company employee class 
 *
 * @Author wang suo
 * @Date 2020/12/22 0022 19:11
 * @Version 1.0
 */
public abstract class AbstractCorp {
    /**
     *  Everyone in the company has a name 
     */
    private String name = "";
    /**
     *  Everyone in the company has a position 
     */
    private String position = "";
    /**
     *  Everyone in the company has a salary 
     */
    private int salary = 0;

    /**
     *  Construction method 
     *
     * @param name      name 
     * @param position  Position 
     * @param salary    salary 
     */
    public AbstractCorp(String name, String position, int salary) {
        this.name = name;
        this.position = position;
        this.salary = salary;
    }

    /**
     *  Get employee information 
     *
     * @return  Information 
     */
    public String getInfo() {
        String info = "";
        info = " name : " + this.name;
        info = info + "\t Position : " + this.position;
        info = info + "\t salary : " + this.salary;
        return info;
    }
}

The branch node

/**
 *  The branch node 
 *
 * @Author wang suo
 * @Date 2020/12/22 0022 20:19
 * @Version 1.0
 */
public class Branch extends AbstractCorp {
    /**
     *  What are the junior leaders and soldiers under the leadership 
     */
    private List<AbstractCorp> subordinateList = new ArrayList<>();

    /**
     *  Construction method 
     *
     * @param name      name 
     * @param position  Position 
     * @param salary    salary 
     */
    public Branch(String name, String position, int salary) {
        super(name, position, salary);
    }

    /**
     *  Add a subordinate 
     *
     * @param corp  The branches of the 
     */
    public void addSubordinate(AbstractCorp corp) {
        subordinateList.add(corp);
    }

    /**
     *  Who I have 
     *
     * @return  Return to your subordinates 
     */
    public List<AbstractCorp> getSubordinate() {
        return subordinateList;
    }
}

Leaf nodes :

/**
 *  leaf 
 *
 * @Author wang suo
 * @Date 2020/12/22 0022 20:29
 * @Version 1.0
 */
public class Leaf extends AbstractCorp {
    /**
     *  Construction method 
     *
     * @param name      name 
     * @param position  Position 
     * @param salary    salary 
     */
    public Leaf(String name, String position, int salary) {
        super(name, position, salary);
    }
}

The modified scene class :

/**
 *  The modified scene class 
 *
 * @Author wang suo
 * @Date 2020/12/22 0022 20:26
 * @Version 1.0
 */
public class Client {

    public static void main(String[] args) {
        // The first is to assemble an organizational structure 
        Branch ceo = compositeCorpTree();

        // First turn on the CEO The information is printed out :
        System.out.println(ceo.getInfo());

        // Then there's all the employee information 
        System.out.println(getTreeInfo(ceo));
    }

    // Put the whole tree together 
    public static Branch compositeCorpTree() {
        // First, the general manager CEO
        Branch root = new Branch(" Wang damazi ", " The general manager ", 100000);
        // Bring out three department managers 
        Branch developDep = new Branch(" Big Liu lame ", " R & D Manager ", 10000);
        Branch salesDep = new Branch(" Ma er Guaizi ", " Sales Manager ", 20000);
        Branch financeDep = new Branch(" Zhao santuozi ", " Finance Manager ", 30000);

        // And then the three team leaders will be produced 
        Branch firstDevGroup = new Branch(" Yang sanmuchi ", " Development team leader ", 5000);
        Branch secondDevGroup = new Branch(" Wu stick mallet ", " Leader of development group 2 ", 6000);

        // Bring out all the minions 
        Leaf a = new Leaf("a", " Developer ", 2000);
        Leaf b = new Leaf("b", " Developer ", 2000);
        Leaf c = new Leaf("c", " Developer ", 2000);
        Leaf d = new Leaf("d", " Developer ", 2000);
        Leaf e = new Leaf("e", " Developer ", 2000);
        Leaf f = new Leaf("f", " Developer ", 2000);
        Leaf g = new Leaf("g", " Developer ", 2000);
        Leaf h = new Leaf("h", " Salesman ", 5000);
        Leaf i = new Leaf("i", " Salesman ", 4000);
        Leaf j = new Leaf("j", " financial staff ", 5000);
        Leaf k = new Leaf("k", "CEO secretary ", 8000);
        Leaf zhengLaoLiu = new Leaf(" Zheng Laoliu ", " Deputy manager of R & D department ", 20000);

        // Start assembling 
        //CEO There are three department managers and a secretary 
        root.addSubordinate(k);
        root.addSubordinate(developDep);
        root.addSubordinate(salesDep);
        root.addSubordinate(financeDep);

        // R & D Manager 
        developDep.addSubordinate(zhengLaoLiu);
        developDep.addSubordinate(firstDevGroup);
        developDep.addSubordinate(secondDevGroup);

        // Let's see what's under the two development teams 
        firstDevGroup.addSubordinate(a);
        firstDevGroup.addSubordinate(b);
        firstDevGroup.addSubordinate(c);
        secondDevGroup.addSubordinate(d);
        secondDevGroup.addSubordinate(e);
        secondDevGroup.addSubordinate(f);

        // Let's look at the personnel in the sales department 
        salesDep.addSubordinate(h);
        salesDep.addSubordinate(i);

        // The last Finance 
        financeDep.addSubordinate(j);

        return root;
    }

    public static String getTreeInfo(Branch root) {
        List<AbstractCorp> subordinateList = root.getSubordinate();
        String info = "";
        for (AbstractCorp corp : subordinateList) {
            if (corp instanceof Leaf) {
                info = info + corp.getInfo() + "\n";
            } else {
                //  It's a little leader 
                info = info + corp.getInfo() + "\n" + getTreeInfo((Branch) corp);
            }
        }
        return info;
    }
}

This is it. Portfolio model .

Portfolio model

Combination pattern is also called composition pattern , Something is also called part - The whole model , It is mainly used to describe the relationship between the whole and the parts .

General class diagram of composite pattern :

Abstract components

public abstract class Component {
	
	// Shared by both individuals and the whole 
	public void doSomething(){
		// Write business logic 
	}
}

Tree branches

public class Composite extends Component {
	// Component containers 
	private ArrayList<Component> componentArrayList = new ArrayList<Component>();
	
	// Add a leaf or branch component 
	public void add(Component component){
		this.componentArrayList.add(component);
	}
	
	// Delete a leaf or branch component 
	public void remove(Component component){
		this.componentArrayList.remove(component);
	}
	
	// Get all the leaf and branch components under the branch 
	public ArrayList<Component> getChildren(){
		return this.componentArrayList;
	}
}

Leaf components

public class Leaf extends Component {
	/*
	 *  You can override the parent method 
	 * public void doSomething(){
	 * 
	 * }
	 */
}

The environment class

public class Client {

	public static void main(String[] args) {
		// Create a root node 
		Composite root = new Composite();
		root.doSomething();
		
		// Create a branch component 
		Composite branch = new Composite();
		// Create a leaf node 
		Leaf leaf = new Leaf();
		
		// Build the whole 
		root.add(branch);
		branch.add(leaf);		
	}
	
	// Traversing the tree recursively 
	public static void display(Composite root){

		for(Component c:root.getChildren()){
			if(c instanceof Leaf){ // Leaf node 
				c.doSomething();
			}else{ // The branch node 
				display((Composite)c);
			}
		}
		
	}
}

We found that in the environment class, we use

Composite root = new Composite();

This one , Violation of the principle of Dependence Inversion .


Let's analyze the advantages and disadvantages of the combination pattern :

  • advantage
    • High level modules are easy to call : Part and whole are no different for the caller ;
    • Nodes are free to increase : Very easy to expand , Comply with opening and closing principle ;
  • shortcoming
    • Violation of the principle of Dependence Inversion ;

Two implementations of the composite pattern

In fact, there are two ways to realize the combination mode , Namely Transparent mode and safe mode , We used security mode above , So what is transparent mode like ?

The class diagram is as follows :

When we compare it with the security model, it's very clear , The transparent pattern is to put all the methods in the abstract class , This is not safe for leaf nodes , Because there will be problems during the run .

Participation of this paper Tencent cloud media sharing plan , You are welcome to join us , share .

版权声明
本文为[wsuo]所创,转载请带上原文链接,感谢
https://cdmana.com/2020/12/20201225111921898Z.html

Scroll to Top