During the daily development process . Tree structure is used very frequently .
for example : Company structure 、 Various classification structures 、 Grouping structure, etc .



SET FOREIGN_KEY_CHECKS = 0; CREATE TABLE IF NOT EXISTS `tbl_sapo_group` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT ' Primary key ', `code` varchar(100) NOT NULL COMMENT ' Unique code ', `create_time` datetime(3) NOT NULL COMMENT ' Creation time ', `last_update_time` datetime(3) DEFAULT NULL COMMENT ' Last update time ', `name` varchar(255) NOT NULL COMMENT ' name ', `detail` varchar(255) DEFAULT NULL COMMENT ' details ', `status` int(10) unsigned NOT NULL DEFAULT 2 COMMENT ' state :0- Invalid ,1- It works ,2- edit ', `group_type` varchar(100) NOT NULL COMMENT ' Group type ', PRIMARY KEY (`id`), UNIQUE KEY `uni_idx_group_code` (`code`), KEY `idx_group_group_type` (`group_type`), CONSTRAINT `fk_group_group_type` FOREIGN KEY (`group_type`) REFERENCES `tbl_sapo_group_type` (`code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=' Group '; CREATE TABLE IF NOT EXISTS `tbl_sapo_group_rel` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT ' Primary key ', `create_time` datetime(3) NOT NULL COMMENT ' Creation time ', `last_update_time` datetime(3) DEFAULT NULL COMMENT ' Last update time ', `parent_code` varchar(100) NOT NULL COMMENT ' Parent node code ,tbl_sapo_group surface code', `child_code` varchar(100) NOT NULL COMMENT ' Child node code ,tbl_sapo_group surface code', `status` int(10) unsigned NOT NULL DEFAULT 2 COMMENT ' state :0- Invalid ,1- It works ,2- edit ', `group_rel_type` varchar(100) NOT NULL COMMENT ' Group relationship type code , come from tbl_sapo_group_rel_type surface code', `tree_code` varchar(100) NOT NULL COMMENT ' Tree node code ,tbl_sapo_tree surface code', PRIMARY KEY (`id`), KEY `idx_group_rel_child_code` (`child_code`), KEY `idx_group_rel_parent_code` (`parent_code`), KEY `idx_group_rel_group_rel_type` (`group_rel_type`), KEY `idx_group_rel_tree_code_status_parent_code_child_code` (`tree_code`,`status`,`parent_code`,`child_code`), CONSTRAINT `fk_group_rel_child_code` FOREIGN KEY (`child_code`) REFERENCES `tbl_sapo_group` (`code`), CONSTRAINT `fk_group_rel_group_rel_type` FOREIGN KEY (`group_rel_type`) REFERENCES `tbl_sapo_group_rel_type` (`code`), CONSTRAINT `fk_group_rel_parent_code` FOREIGN KEY (`parent_code`) REFERENCES `tbl_sapo_group` (`code`), CONSTRAINT `fk_group_rel_tree_code` FOREIGN KEY (`tree_code`) REFERENCES `tbl_sapo_tree` (`code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=' Group relationship '; CREATE TABLE IF NOT EXISTS `tbl_sapo_group_rel_type` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT ' Primary key ', `code` varchar(100) NOT NULL COMMENT ' Unique code ', `create_time` datetime(3) NOT NULL COMMENT ' Creation time ', `last_update_time` datetime(3) DEFAULT NULL COMMENT ' Last update time ', `name` varchar(255) NOT NULL COMMENT ' name ', `detail` varchar(255) DEFAULT NULL COMMENT ' details ', `status` int(10) unsigned NOT NULL DEFAULT 2 COMMENT ' state :0- Invalid ,1- It works ,2- edit ', PRIMARY KEY (`id`), UNIQUE KEY `uni_idx_group_rel_type_code` (`code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=' Group relationship type '; CREATE TABLE IF NOT EXISTS `tbl_sapo_group_type` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT ' Primary key ', `code` varchar(100) NOT NULL COMMENT ' Unique code ', `create_time` datetime(3) NOT NULL COMMENT ' Creation time ', `last_update_time` datetime(3) DEFAULT NULL COMMENT ' Last update time ', `name` varchar(255) NOT NULL COMMENT ' name ', `detail` varchar(255) DEFAULT NULL COMMENT ' details ', `status` int(10) unsigned NOT NULL DEFAULT 2 COMMENT ' state :0- Invalid ,1- It works ,2- edit ', PRIMARY KEY (`id`), UNIQUE KEY `uni_idx_group_type_code` (`code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=' Group type '; CREATE TABLE IF NOT EXISTS `tbl_sapo_tree` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT ' Primary key ', `code` varchar(100) NOT NULL COMMENT ' Unique code ', `create_time` datetime(3) NOT NULL COMMENT ' Creation time ', `last_update_time` datetime(3) DEFAULT NULL COMMENT ' Last update time ', `name` varchar(255) NOT NULL COMMENT ' name ', `detail` varchar(255) DEFAULT NULL COMMENT ' details ', `status` int(10) unsigned NOT NULL DEFAULT 2 COMMENT ' state :0- Invalid ,1- It works ,2- edit ', PRIMARY KEY (`id`), UNIQUE KEY `uni_idx_tree_code` (`code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=' Tree definition '; CREATE TABLE IF NOT EXISTS `tbl_sapo_tree_group` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT ' Primary key ', `create_time` datetime(3) NOT NULL COMMENT ' Creation time ', `last_update_time` datetime(3) DEFAULT NULL COMMENT ' Last update time ', `group_code` varchar(100) NOT NULL COMMENT ' Group code ,tbl_sapo_group surface code', `tree_code` varchar(100) NOT NULL COMMENT ' Tree code ,tbl_sapo_tree surface code', `status` int(10) unsigned NOT NULL DEFAULT 2 COMMENT ' state :0- Invalid ,1- It works ,2- edit ', `is_root` int(10) unsigned DEFAULT NULL COMMENT ' Whether the root node :1- The root node ,null Non root node ', PRIMARY KEY (`id`), UNIQUE KEY `uni_idx_tree_group_tree_code_is_root` (`tree_code`,`is_root`), KEY `idx_tree_group_group_code` (`group_code`), CONSTRAINT `fk_tree_group_group_code` FOREIGN KEY (`group_code`) REFERENCES `tbl_sapo_group` (`code`), CONSTRAINT `fk_tree_group_tree_code` FOREIGN KEY (`tree_code`) REFERENCES `tbl_sapo_tree` (`code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=' Groups contained in the tree '; SET FOREIGN_KEY_CHECKS = 1;
As shown in the figure, the relational database model , It basically meets the requirements of multiple trees in a system 、 The purpose for which groups can be reused .
The node of the tree may be a single node , It may also be the root of a subtree . When we need to traverse, we need different processing from different nodes , Use 【 polymorphic 】.
But don't distinguish which node it is when processing , Provide a kind of 【 Transparency 】 Processing mode , To implement, you need to reference two patterns : Iterative mode 、 Portfolio model
Old rules , First introduce the concept , After that .
| Iterator pattern | Provides a way to traverse a collection without exposing its implementation |
| Portfolio model | Customers can treat collections of objects as well as individual objects equally |
Iterator pattern :
![]()
| Iterator example : Array implementation iterator
![]() // Iterator interface interface Iterator { boolean hasNext(); Object next(); } // A menu item class MenuItem { String name; String description; boolean vegetarian; double price; public MenuItem(String name, String description, boolean vegetarian, double price) { this.name = name; this.description = description; this.vegetarian = vegetarian; this.price = price; } // getter,setter Method public String getName() { return name; } } // menu class DinerMenu { static final int MAX_ITEMS = 6; int numberOfItems = 0; MenuItem[] menuItems; public DinerMenu() { menuItems = new MenuItem[MAX_ITEMS]; addItem(" Stewed Pork Ball in Brown Sauce ", " Jiangnan famous dishes ", true, 50d); addItem(" Pork Lungs in Chili Sauce ", " It has nothing to do with husband and wife ", true, 70d); } public void addItem(String name, String description, boolean vegetarian, double price) { MenuItem menuItem = new MenuItem(name, description, vegetarian, price); if (numberOfItems >= MAX_ITEMS) { System.out.println("sorry,menu is full"); } else { menuItems[numberOfItems] = menuItem; numberOfItems += 1; } } public MenuItem[] getMenuItems() { return menuItems; } public Iterator createIteator() { return new DinerMenuIterator(menuItems); } } class DinerMenuIterator implements Iterator { MenuItem[] items; int position = 0; public DinerMenuIterator(MenuItem[] items) { this.items = items; } public Object next() { MenuItem menuItem = items[position]; position = position + 1; return menuItem; } public boolean hasNext() { // The array may not be full if (position >= items.length || items[position] == null) { return false; } else { return true; } } public void remove() { if (position <= 0) { throw new IllegalStateException("you can't an item unitl you've done at least on next()"); } if (items[position - 1] != null) { for (int i = position - 1; i < (items.length - 1); i++) { items[i] = items[i + 1]; } items[items.length - 1] = null; } } } // test class Test { public static void main(String[] args) { Iterator iterator = (new DinerMenu()).createIteator(); while(iterator.hasNext()){ MenuItem menuItem = (MenuItem) iterator.next(); System.out.println(menuItem.getName()); } } } Example iterator pattern 1. Of course remove Can not be realized , Because it may be concurrent remove, Iterators are unsafe . We simply deal with throwing java.lang.UnsupportedOperationException 2.java5 after , Collections can be used for/in The form replaces the creation iterator shown . for( Object obj: collection){ } |
For different sets , We have different traversal methods . Is there a general pattern for traversing collections , Shield this difference , This pattern is the iterator .
The iterator pattern provides a way to access the elements of an aggregate object sequentially , Without exposing its internal representation .
In fact, it's plain , The iterator pattern is defined by defining a unified operation interface , To shield different underlying operating logic .
If you can have a unified method to access every object in the aggregation , You can write Polymorphic code matches these aggregations .
Put the wandering task on the iterator , Instead of aggregating . This simplifies the interface and implementation of aggregation . Clear distribution of responsibilities .
accord with 【 Single responsibility 】, If you do not use the iterator pattern , If the set changes , For example, from a set to an array , This class must be changed , The traversal mode also changes .
Portfolio model :
Allows you to combine objects into a tree structure to represent “ whole / part ” hierarchy .
Composition allows customers to handle individual objects and composition of objects in a consistent way . That is, we can ignore the differences between object combinations and individual objects , Use the same operation .
Composite mode sacrifice 【 Single responsibility 】 obtain 【 transparency 】, Transparency means that customer processing combinations and leaf nodes are treated equally . Whether a node is a combination or a leaf node , Transparent to customers .
![]()
| Examples of combination patterns :
![]() public abstract class MenuComponent { // Operation nodes require methods public void add(MenuComponent menuComponent) { throw new UnsupportedOperationException(); } public void remove(MenuComponent menuComponent) { throw new UnsupportedOperationException(); } public MenuComponent getChild(int i) { throw new UnsupportedOperationException(); } // The menu itself public String getName() { throw new UnsupportedOperationException(); } public String getDescription() { throw new UnsupportedOperationException(); } public double getPrice() { throw new UnsupportedOperationException(); } public boolean isVegetarian() { throw new UnsupportedOperationException(); } public void print() { throw new UnsupportedOperationException(); } } ![]() public class Menu extends MenuComponent { ArrayList<MenuComponent> menuComponents = new ArrayList<MenuComponent>(); String name; String description; public Menu(String name, String description) { this.name = name; this.description = description; } public void add(MenuComponent menuComponent) { menuComponents.add(menuComponent); } public void remove(MenuComponent menuComponent) { menuComponents.remove(menuComponent); } public MenuComponent getChild(int i) { return (MenuComponent) menuComponents.get(i); } public String getName() { return name; } public String getDescription() { return description; } public void print() { System.out.print("\n" + getName()); System.out.println(", " + getDescription()); System.out.println("---------------------"); Iterator<MenuComponent> iterator = menuComponents.iterator(); while (iterator.hasNext()) { MenuComponent menuComponent = (MenuComponent) iterator.next(); menuComponent.print(); } } } ![]() public class MenuItem extends MenuComponent { String name; String description; boolean vegetarian; double price; public MenuItem(String name, String description, boolean vegetarian, double price) { this.name = name; this.description = description; this.vegetarian = vegetarian; this.price = price; } public String getName() { return name; } public String getDescription() { return description; } public double getPrice() { return price; } public boolean isVegetarian() { return vegetarian; } public void print() { System.out.print(" " + getName()); if (isVegetarian()) { System.out.print("(v)"); } System.out.println(", " + getPrice()); System.out.println(" -- " + getDescription()); } } ![]() public class Waitress { MenuComponent allMenus; public Waitress(MenuComponent allMenus) { this.allMenus = allMenus; } public void printMenu() { allMenus.print(); } }
|
Example :
Use iteration and composition patterns to implement a common tree structure :
1. Core and group to group relationships .
2. The scheme was implemented , Internal iterators and external iterators . Use according to the actual situation .
![]()
| ![]()
|

public abstract class GroupComponent { public abstract Iterator<GroupComponent> createIterator(); // The first line of characters is a few spaces empty protected abstract String printTreeStr(int i); public abstract String getName(); public String printTreeStr() { return printTreeStr(0); }; // Print tree solution structure protected String padding_n(int n) { StringBuffer space = new StringBuffer(""); for (int i = 0; i < n; i++) { space.append("-"); } space.append("|"); return space.toString(); } // Get the tree structure recursively public static GroupComponent getTree(String groupCode) { // Get general dao CommonDao dao = SpringUtil.getBean(CommonDao.class); // Group details in the database model class SapoGroup sapoGroup = dao.getObj(SapoGroup.getInstance().setCode(groupCode)); // Query all the sons of this node List<SapoGroupRel> childList = dao.getObjListWithEmpty(SapoGroupRel.getInstance().setParentCode(groupCode)); // If there are no child nodes , Directly create a new leaf node and return if (childList == null || childList.size() == 0) { LeafGroup leafGroup = new LeafGroup(); leafGroup.setLeafGroup(sapoGroup); return leafGroup; } else { // If there are child nodes Group group = new Group(); group.setGroupDetail(sapoGroup); for (SapoGroupRel rel : childList) { // Recursively get the previous node GroupComponent child = getTree(rel.getChildCode()); group.getList().add(child); } return group; } } }

public class Group extends GroupComponent { Iterator<GroupComponent> iterator = null; public List<GroupComponent> list = new ArrayList<GroupComponent>(); public SapoGroup groupDetail; public SapoGroup getGroupDetail() { return groupDetail; } public void setGroupDetail(SapoGroup groupDetail) { this.groupDetail = groupDetail; } /* * Print tree hierarchy */ protected String printTreeStr(int i) { // Fields to be printed String waitPrintStr = this.groupDetail.getName(); StringBuilder sb = new StringBuilder(); sb.append(padding_n(i)); sb.append(waitPrintStr); sb.append("\r\n"); Iterator<GroupComponent> iterator = list.iterator(); while (iterator.hasNext()) { GroupComponent next = iterator.next(); // Recursive traversal String printTree = next.printTreeStr(i + 2); sb.append(printTree); } return sb.toString(); } public List<GroupComponent> getList() { return list; } public void setList(List<GroupComponent> list) { this.list = list; } @Override public Iterator<GroupComponent> createIterator() { if (iterator == null) { iterator = new GroupIterator(list.iterator()); } return iterator; } @Override public String getName() { return "list: " + groupDetail.getName(); } }

public class LeafGroup extends GroupComponent { private SapoGroup leafGroup; public SapoGroup getLeafGroup() { return leafGroup; } public void setLeafGroup(SapoGroup leafGroup) { this.leafGroup = leafGroup; } public Iterator<GroupComponent> createIterator() { return new NullIterator(); } protected String printTreeStr(int i) { // Key fields String waitPrintStr = this.getLeafGroup().getName(); return padding_n(i) + waitPrintStr + "\r\n"; } /* (non-Javadoc) * @see cn.com.fmsh.nfcos.sapo.biz.testGroup.GroupComponent#getName() */ @Override public String getName() { return "leaf: "+leafGroup.getName(); } }

public class GroupIterator implements Iterator<GroupComponent> { Stack<Iterator<GroupComponent>> stack = new Stack<Iterator<GroupComponent>>(); public GroupIterator(Iterator<GroupComponent> iterator) { stack.push(iterator); } public boolean hasNext() { if (stack.isEmpty()) { return false; } else { Iterator<GroupComponent> iterator = stack.peek(); if (!iterator.hasNext()) { stack.pop(); return hasNext(); } else { return true; } } } public GroupComponent next() { if(hasNext()) { Iterator<GroupComponent> iterator = stack.peek(); GroupComponent next = iterator.next(); stack.push(next.createIterator()); return next; }else { return null; } } }

public class NullIterator implements Iterator<GroupComponent> { public GroupComponent next() { return null; } public boolean hasNext() { return false; } }
The test program , Traverse the tree structure 、 Print tree structure .
@Test public void Test() { // Use an external iterator to traverse GroupComponent tree = Group.getTree("hotel"); Iterator<GroupComponent> iterator = tree.createIterator(); while (iterator.hasNext()) { GroupComponent next = iterator.next(); // TODO Traverse the operation contents } System.out.println("---- Print tree structure -----"); // Print tree structure System.err.println(GroupComponent.getTree("hotel").printTreeStr()); }

This article is from the blog Garden , author :wanglifeng, Reprint please indicate the original link :https://www.cnblogs.com/wanglifeng717/p/16363485.html












![[Day2 intensive literature reading] time in the mind: using space to think about time](/img/7a/b155ee0c136f911a7e99e9633af246.png)



![[Day9 literature extensive reading] on the (a) symmetry between the perception of time and space in large-scale environments](/img/06/3011aef2e9e26cbc7c63b5c2967df7.png)