0 x0, introduction

In this paper, the corresponding design patterns and paradigms are: structural (53), Composite Pattern, also known as part of the overall Pattern, do not confuse with the combination relationship between classes mentioned above!! The composite pattern is used to process tree-structured data (collections of objects).

Data must be represented in a tree structure, so it is not often used in daily development, but if the data can be represented in a tree structure, this pattern can work wonders (code simplicity).

Tips: Secondary knowledge processing inevitably has mistakes, interested in the time can refer to the original, thank you.


0 x1, definition

Grouping objects into a tree structure to represent a hierarchy of entire sections, allowing users to treat objects and combinations of objects uniformly.

In the clouds? Write a simple example to help understand ~

Write a simple example

Or the example of a milk tea shop (tree structure) :

It is not difficult to break it down into two categories and assume the following requirements:

  • Menu: menu name, description, add or delete sub-menu or drink;
  • Beverage: name, description, price, print information

Here we implement a wave using regular code:

Public abstract class Drink {protected String name; public abstract class Drink {protected String name; protected String desc; protected int price; public Drink(String name, String desc, int price) { this.name = name; this.desc = desc; this.price = price; } protected String printMsg() {return "* [" + name + "] - "+ desc +" - "+ price + "; }} public class FruitTea extends Drink {public FruitTea(String name, String desc, int price) { super(name, desc, price); } } public class IceCream extends Drink { public IceCream(String name, String desc, int price) { super(name, desc, price); } } public class MilkTea extends Drink { public MilkTea(String name, String desc, int price) { super(name, desc, price); }} public class Menu {private String name; private String desc; private List<Menu> subMenus = new ArrayList<>(); private List<FruitTea> fruitTeas = new ArrayList<>(); private List<IceCream> iceCreams = new ArrayList<>(); private List<MilkTea> milkTeas = new ArrayList<>(); public Menu(String name, String desc) { this.name = name; this.desc = desc; } void addMenu(Menu menu) { subMenus.add(menu); } void addFruitTea(FruitTea tea) { fruitTeas.add(tea); } void addIceCream(IceCream iceCream) { iceCreams.add(iceCream); } void addMilkTea(MilkTea tea) { milkTeas.add(tea); } String printMsg() {StringBuilder sb = new StringBuilder(" + name + ":" + desc); For (Menu: menus) {sb.append("\n【 subMenus 】 → ").append(menu.name).append(":").append(menu.desc).append("\n"); for(FruitTea tea: menu.fruitTeas) { sb.append(tea.printMsg()).append("\n"); } for(IceCream iceCream: menu.iceCreams) { sb.append(iceCream.printMsg()).append("\n"); } for(MilkTea milkTea: menu.milkTeas) { sb.append(milkTea.printMsg()).append("\n"); } } return sb.toString(); }} // Test case (add drinks to the menu, Public class MenuTest {public static void main(String[] args) {Menu mainMenu = new Menu(" mainMenu ", "Includes submenu and all drinks "); Menu fruitTeaMenu = new Menu(" fruit tea ", "real fruit tea "); Menu iceCreamMenu = new Menu(" ice cream ", "fresh ice cream "); Menu milkTeaMenu = new Menu(" milk tea ", "freshly cooked milk tea "); LemonWater = new FruitTea lemonWater (" fruit juice ", "fruit juice ", 5); FruitTea hitOrange = new FruitTea(" Stick beat fresh orange ", "Shenzhen orange popularity soared no. 5 ", 7); IceCream milkShake = new IceCream(" strawberry shake ", "this restaurant is popular no. 4 ", 7); IceCream sundae = new IceCream(" Strawberry Snow King Big Sundae ", "Longgang District strawberry Sundae popularity surge no. 4 ", 7); MilkTea jelly = new MilkTea(" grandma baked fairy grass (large cup)", "now boil tender smooth baked fairy grass ", 10); MilkTea MilkTea = new MilkTea(" ba ba coconut MilkTea ", "Q pop coconut MilkTea, blended with aromatic MilkTea ", 9); fruitTeaMenu.addFruitTea(lemonWater); fruitTeaMenu.addFruitTea(hitOrange); iceCreamMenu.addIceCream(milkShake); iceCreamMenu.addIceCream(sundae); milkTeaMenu.addMilkTea(jelly); milkTeaMenu.addMilkTea(milkTea); mainMenu.addMenu(fruitTeaMenu); mainMenu.addMenu(iceCreamMenu); mainMenu.addMenu(milkTeaMenu); System.out.println(mainMenu.printMsg()); }}Copy the code

The output is as follows:

The above implementation method, add or delete drinks or sub-menu, the original code to be modified in several places, poor scalability. For this scenario, which can be represented as a tree structure and business requirements are realized through recursive traversal, the combined mode can be directly transformed:

Public abstract class AbstractComponent {abstractvoid add(AbstractComponent component); public abstractclass AbstractComponent {abstractvoid add(AbstractComponent component); abstract AbstractComponent get(int index); abstract String printMsg(); Public class AbstractDrink extends AbstractComponent {protected String name;} public class AbstractDrink extends AbstractComponent {protected String name; protected String desc; protected int price; public AbstractDrink(String name, String desc, int price) { this.name = name; this.desc = desc; this.price = price; } @override AbstractComponent get(int index) {return} @override AbstractComponent get(int index) {return} @override AbstractComponent get(int index) null; } @override String printMsg() {return "* [" + name + "] - "+ desc +" - "+ price + "; }} public class FruitTea extends AbstractDrink {public FruitTea(String name, String desc, int price) { super(name, desc, price); } } public class IceCream extends AbstractDrink { public IceCream(String name, String desc, int price) { super(name, desc, price); } } public class MilkTea extends AbstractDrink { public MilkTea(String name, String desc, int price) { super(name, desc, price); Public class AbstractMenu extends AbstractComponent {private String name; private String desc; private List<AbstractComponent> menus; public AbstractMenu(String name, String desc) { this.name = name; this.desc = desc; this.menus = new ArrayList<>(); } @Override void add(AbstractComponent component) { menus.add(component); } @Override AbstractComponent get(int index) { return menus.get(index); } @override String printMsg() {StringBuilder sb = new StringBuilder(" + name + ":" + desc + "\n"); for(AbstractComponent menu: menus) { sb.append(menu.printMsg()).append("\n"); } return sb.toString(); Public class MenuTest {public static void main(String[] args) {AbstractComponent mainMenu = new AbstractMenu(" large menu ", "contains submenus and all drinks "); AbstractComponent fruitTeaMenu = new AbstractMenu(" fruit ", "fruit "); AbstractComponent iceCreamMenu = new AbstractMenu(" iceCreamMenu ", "iceCreamMenu "); AbstractComponent milkTeaMenu = new AbstractMenu(" milk tea ", "freshly cooked milk tea "); AbstractComponent lemonWater = new FruitTea(" fresh fruit ", "AbstractComponent lemonWater ", 5); AbstractComponent hitOrange = new FruitTea; AbstractComponent milkShake = new IceCream(" strawberry shake ", "AbstractComponent milkShake ", 7); AbstractComponent sundae = new IceCream(" strawberry snow King big sundae ", "Longgang strawberry sundae popularity rise no. 4 ", 7); AbstractComponent jelly = new MilkTea(" 大 吃 香 肠 ", "香 肠 ", 10); AbstractComponent milkTea = new milkTea (" ba ba coconut milkTea ", "Q pop coconut milkTea ", 9); ~ fruitteamenu. add(lemonWater); fruitTeaMenu.add(hitOrange); iceCreamMenu.add(milkShake); iceCreamMenu.add(sundae); milkTeaMenu.add(jelly); milkTeaMenu.add(milkTea); mainMenu.add(fruitTeaMenu); mainMenu.add(iceCreamMenu); mainMenu.add(milkTeaMenu); System.out.println(mainMenu.printMsg()); }}Copy the code

The output is as follows:

The code looks a lot, but it’s actually very simple, and perfectly echoes the two keys of the combination pattern: tree structure + uniform treatment. Along the way, draw a UML class diagram and role introduction:

  • Component (Abstract Component) → Declare interface for composite objects, through which clients access and manage the entire object structure;
  • Composite (container components) → Inherit abstract components, containing multiple nodes of the Composite object, it can also have other container components or leaf components;
  • Leaf (Leaf component) → Inherits abstract component, defines the behavior that implements the Leaf object, atomic object, which has no other component under it.

In addition, depending on whether the abstract component declares methods for managing its members, it is divided into: Transparent composition mode and safe composition mode, the above example is the standard form of transparent composition mode. The advantage of transparent composition mode is that all component classes have the same interface. The disadvantage of transparent composition mode is that it is not safe. But the run-time call can go wrong (if no error-handling code for the response is provided)

Advantages:

Clients don’t have to worry about whether they’re dealing with composite objects or leaf objects, don’t have to write a bunch of if statements to make sure that the right method is called on the right object, and usually just need to call a method and perform an operation on the entire structure.

Disadvantages:

The addition of new components brings some problems, such as the difficulty of restricting the component types in the composition, the detection of component types cannot be done by the compiler type bundle, and must be dynamically detected at run time.

Some classic examples of composite patterns:

  • java.awt
  • Java collection
  • Mybatis SqlNode

Limited to the space is not opened, examples in detail: design | combination model and typical applications