主頁 > 軟體設計 > 通用樹形結構的迭代與組合模式實作方案

通用樹形結構的迭代與組合模式實作方案

2022-07-13 20:26:17 軟體設計

日常開發程序程序中,樹形結構運用的非常頻繁,

例如:公司組織結構、各種分類結構、分組結構等等,

 

 

 

 

SET FOREIGN_KEY_CHECKS = 0;

CREATE TABLE IF NOT EXISTS `tbl_sapo_group` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `code` varchar(100) NOT NULL COMMENT '唯一編碼',
  `create_time` datetime(3) NOT NULL COMMENT '創建時間',
  `last_update_time` datetime(3) DEFAULT NULL COMMENT '最后更新時間',
  `name` varchar(255) NOT NULL COMMENT '名稱',
  `detail` varchar(255) DEFAULT NULL COMMENT '詳情',
  `status` int(10) unsigned NOT NULL DEFAULT 2 COMMENT '狀態:0-無效,1-有效,2-編輯',
  `group_type` varchar(100) NOT NULL COMMENT '組型別',
  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='';

CREATE TABLE IF NOT EXISTS `tbl_sapo_group_rel` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `create_time` datetime(3) NOT NULL COMMENT '創建時間',
  `last_update_time` datetime(3) DEFAULT NULL COMMENT '最后更新時間',
  `parent_code` varchar(100) NOT NULL COMMENT '父節點代碼,tbl_sapo_group表code',
  `child_code` varchar(100) NOT NULL COMMENT '子節點代碼,tbl_sapo_group表code',
  `status` int(10) unsigned NOT NULL DEFAULT 2 COMMENT '狀態:0-無效,1-有效,2-編輯',
  `group_rel_type` varchar(100) NOT NULL COMMENT '組關系型別代碼,來自tbl_sapo_group_rel_type表code',
  `tree_code` varchar(100) NOT NULL COMMENT '樹節點代碼,tbl_sapo_tree表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='組關系';

CREATE TABLE IF NOT EXISTS `tbl_sapo_group_rel_type` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `code` varchar(100) NOT NULL COMMENT '唯一編碼',
  `create_time` datetime(3) NOT NULL COMMENT '創建時間',
  `last_update_time` datetime(3) DEFAULT NULL COMMENT '最后更新時間',
  `name` varchar(255) NOT NULL COMMENT '名稱',
  `detail` varchar(255) DEFAULT NULL COMMENT '詳情',
  `status` int(10) unsigned NOT NULL DEFAULT 2 COMMENT '狀態:0-無效,1-有效,2-編輯',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uni_idx_group_rel_type_code` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='組關系型別';

CREATE TABLE IF NOT EXISTS `tbl_sapo_group_type` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `code` varchar(100) NOT NULL COMMENT '唯一編碼',
  `create_time` datetime(3) NOT NULL COMMENT '創建時間',
  `last_update_time` datetime(3) DEFAULT NULL COMMENT '最后更新時間',
  `name` varchar(255) NOT NULL COMMENT '名稱',
  `detail` varchar(255) DEFAULT NULL COMMENT '詳情',
  `status` int(10) unsigned NOT NULL DEFAULT 2 COMMENT '狀態:0-無效,1-有效,2-編輯',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uni_idx_group_type_code` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='組型別';

CREATE TABLE IF NOT EXISTS `tbl_sapo_tree` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `code` varchar(100) NOT NULL COMMENT '唯一編碼',
  `create_time` datetime(3) NOT NULL COMMENT '創建時間',
  `last_update_time` datetime(3) DEFAULT NULL COMMENT '最后更新時間',
  `name` varchar(255) NOT NULL COMMENT '名稱',
  `detail` varchar(255) DEFAULT NULL COMMENT '詳情',
  `status` int(10) unsigned NOT NULL DEFAULT 2 COMMENT '狀態:0-無效,1-有效,2-編輯',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uni_idx_tree_code` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='樹定義';

CREATE TABLE IF NOT EXISTS `tbl_sapo_tree_group` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `create_time` datetime(3) NOT NULL COMMENT '創建時間',
  `last_update_time` datetime(3) DEFAULT NULL COMMENT '最后更新時間',
  `group_code` varchar(100) NOT NULL COMMENT '組代碼,tbl_sapo_group表code',
  `tree_code` varchar(100) NOT NULL COMMENT '樹代碼,tbl_sapo_tree表code',
  `status` int(10) unsigned NOT NULL DEFAULT 2 COMMENT '狀態:0-無效,1-有效,2-編輯',
  `is_root` int(10) unsigned DEFAULT NULL COMMENT '是否根節點:1-根節點,null非根節點',
  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='樹包含的組';

SET FOREIGN_KEY_CHECKS = 1;
建表陳述句

如圖所示關系型資料庫模型,基本滿足一個系統多顆樹、組可以復用的目的,

 

樹的節點可能是一個單獨的節點,也可能是一個子樹的根,我們需要遍歷的時候需要不同節點不同處理,使用【多型】,

但是處理的時候不要區分是何種節點,提供一種【透明化】處理方式,要實作需要參考兩個模式:迭代模式、組合模式

老規矩,先引入概念,之后實作,

迭代器模式 提供一個方式來遍歷集合而無需暴露集合的實作
組合模式 客戶可以將物件的集合以及個別物件一視同仁

 

迭代器模式:

 

 

迭代器示例:陣列實作迭代器

 

 

// 迭代器介面
interface Iterator {
    boolean hasNext();

    Object next();
}

// 選單項
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方法
    public String getName() {
        return name;
    }
}

// 選單
class DinerMenu {
    static final int MAX_ITEMS = 6;
    int numberOfItems = 0;
    MenuItem[] menuItems;

    public DinerMenu() {
        menuItems = new MenuItem[MAX_ITEMS];
        addItem("紅燒獅子頭", "江南名菜", true, 50d);
        addItem("夫妻肺片", "和夫妻沒啥關系", 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() {
        // 陣列可能沒裝滿
        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;
        }

    }

}

// 測驗
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());
        }

    }
}
迭代器模式示例
陣列迭代器

1.當然remove可以不實作,因為可能并發remove,迭代器不安全,

我們簡單處理拋出java.lang.UnsupportedOperationException

2.java5之后,集合可以使用for/in形式代替了顯示的創建迭代器,

for( Object obj: collection){

}

 

對于不同的集合,我們有不同的遍歷方式,有沒有一種通用的遍歷集合的模式,屏蔽這種差異,該模式就是迭代器,

迭代器模式提供一種方法順序訪問一個聚合物件中的各個元素,而不暴露其內部的表示,

其實說白了,迭代器模式就是通過定義統一操作介面,來屏蔽不同底層的操作邏輯,

如果你能有一個統一的方法訪問聚合中的每一個物件,你就可以撰寫多型的代碼和這些聚合搭配

把游走的任務放在迭代器上,而不是聚合上,這樣簡化了聚合的介面和實作,責任分配明晰,

符合【單一職責】,如果不使用迭代器模式,集合改變的話,例如由集合變陣列,這個類必須改變,遍歷方式也跟著改變,

 

組合模式:

允許你將物件組合成樹形結構來表現“整體/部分”層次結構,

組合能讓客戶以一致的方式處理個別物件以及物件組合,即我們可以忽略物件組合和個別物件之間的差別,而使用相同操作,

組合模式犧牲【單一責任】獲取【透明性】,透明性即客戶處理組合和葉節點一視同仁,一個節點是組合還是葉節點,對客戶是透明的,

 

 

 

 

組合模式示例:

 

 

 

 

public abstract class MenuComponent {
   
    // 操作節點需要方法
    public void add(MenuComponent menuComponent) {
        throw new UnsupportedOperationException();
    }
    public void remove(MenuComponent menuComponent) {
        throw new UnsupportedOperationException();
    }
    public MenuComponent getChild(int i) {
        throw new UnsupportedOperationException();
    }
  
    // 選單本身方法
    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();
    }
}
MenuComponent
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();
        }
    }
}
Menu
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());
    }
}
MenuItem
public class Waitress {
    MenuComponent allMenus;
 
    public Waitress(MenuComponent allMenus) {
        this.allMenus = allMenus;
    }
 
    public void printMenu() {
        allMenus.print();
    }
}
Waitress

 

 示例:

使用迭代和組合模式實作一種通用的樹形結構:

1.核心及組和組的關系,

2.該方案實作了,內部迭代器和外部迭代器,根據實際情況使用,

 

 

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!50503 SET NAMES utf8mb4 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

CREATE TABLE IF NOT EXISTS `tbl_sapo_group` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `code` varchar(100) NOT NULL COMMENT '唯一編碼',
  `create_time` datetime(3) NOT NULL COMMENT '創建時間',
  `last_update_time` datetime(3) DEFAULT NULL COMMENT '最后更新時間',
  `name` varchar(255) NOT NULL COMMENT '名稱',
  `detail` varchar(255) DEFAULT NULL COMMENT '詳情',
  `status` int(10) unsigned NOT NULL DEFAULT 2 COMMENT '狀態:0-無效,1-有效,2-編輯',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uni_idx_group_code` (`code`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 COMMENT='組';

/*!40000 ALTER TABLE `tbl_sapo_group` DISABLE KEYS */;
INSERT INTO `tbl_sapo_group` (`id`, `code`, `create_time`, `last_update_time`, `name`, `detail`, `status`) VALUES
    (1, 'hotel', '2022-06-08 10:25:53.000', NULL, '酒店', NULL, 2),
    (2, '7day', '2022-06-08 10:26:18.000', NULL, '七天', NULL, 2),
    (3, 'rujia', '2022-06-08 10:26:43.000', NULL, '如家', NULL, 2),
    (4, 'wujiaochang', '2022-06-08 10:27:37.000', NULL, '五角場', NULL, 2),
    (5, 'huazhu', '2022-06-08 22:48:23.000', NULL, '華住', NULL, 2),
    (6, 'hanting', '2022-06-08 22:48:43.000', NULL, '漢庭', NULL, 2),
    (7, 'hongkou', '2022-06-09 09:46:57.000', NULL, '虹口足球場', NULL, 2),
    (8, 'jiangwan', '2022-06-09 09:47:22.000', NULL, '江灣', NULL, 2);
/*!40000 ALTER TABLE `tbl_sapo_group` ENABLE KEYS */;

CREATE TABLE IF NOT EXISTS `tbl_sapo_group_rel` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `create_time` datetime(3) NOT NULL COMMENT '創建時間',
  `last_update_time` datetime(3) DEFAULT NULL COMMENT '最后更新時間',
  `parent_code` varchar(100) NOT NULL COMMENT '名稱',
  `child_code` varchar(100) NOT NULL COMMENT '詳情',
  `status` int(10) unsigned NOT NULL DEFAULT 2 COMMENT '狀態:0-無效,1-有效,2-編輯',
  PRIMARY KEY (`id`),
  KEY `fk_tbl_sapo_group_rel_parent_code` (`parent_code`),
  KEY `fk_tbl_sapo_group_rel_child_code` (`child_code`),
  KEY `idx_group_rel_status_parent_child_code` (`status`,`parent_code`,`child_code`) USING BTREE,
  CONSTRAINT `fk_tbl_sapo_group_rel_child_code` FOREIGN KEY (`child_code`) REFERENCES `tbl_sapo_group` (`code`),
  CONSTRAINT `fk_tbl_sapo_group_rel_parent_code` FOREIGN KEY (`parent_code`) REFERENCES `tbl_sapo_group` (`code`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COMMENT='組關系';

/*!40000 ALTER TABLE `tbl_sapo_group_rel` DISABLE KEYS */;
INSERT INTO `tbl_sapo_group_rel` (`id`, `create_time`, `last_update_time`, `parent_code`, `child_code`, `status`) VALUES
    (1, '2022-06-08 10:28:05.000', NULL, 'hotel', '7day', 2),
    (2, '2022-06-08 10:28:19.000', NULL, 'hotel', 'rujia', 2),
    (3, '2022-06-08 10:28:36.000', NULL, '7day', 'wujiaochang', 2),
    (4, '2022-06-08 22:49:00.000', NULL, 'hotel', 'huazhu', 2),
    (5, '2022-06-08 22:49:12.000', NULL, 'hotel', 'hanting', 2),
    (6, '2022-06-09 09:47:58.000', NULL, 'hanting', 'hongkou', 2),
    (7, '2022-06-09 09:48:40.000', NULL, 'hanting', 'jiangwan', 2);
/*!40000 ALTER TABLE `tbl_sapo_group_rel` ENABLE KEYS */;

/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */;
建表及測驗資料

 

 

 

 

public abstract class GroupComponent {

   

    public abstract Iterator<GroupComponent> createIterator();
    
    // 首行字符空幾格
    protected abstract String printTreeStr(int i);
    
    public abstract String getName();
    
    public  String printTreeStr() {
        return printTreeStr(0);
    };
    
    
    
    // 列印樹形解結構
    protected String padding_n(int n) {
        StringBuffer space = new StringBuffer("");
        for (int i = 0; i < n; i++) {
            space.append("-");
        }
        space.append("|");
        return space.toString();
    }
    
 // 遞回獲取樹形結構
    public static GroupComponent getTree(String groupCode) {
        // 獲取通用dao
        CommonDao dao = SpringUtil.getBean(CommonDao.class);
        // 資料庫中組詳細資訊model類
        SapoGroup sapoGroup = dao.getObj(SapoGroup.getInstance().setCode(groupCode));

        // 查詢該節點所有兒子
        List<SapoGroupRel> childList = dao.getObjListWithEmpty(SapoGroupRel.getInstance().setParentCode(groupCode));

        // 如果沒有子節點,直接新建葉子節點回傳
        if (childList == null || childList.size() == 0) {
            LeafGroup leafGroup = new LeafGroup();
            leafGroup.setLeafGroup(sapoGroup);
            return leafGroup;
        } else {
            // 如果有子節點
            Group group = new Group();
            group.setGroupDetail(sapoGroup);
            for (SapoGroupRel rel : childList) {
                // 遞回拿到上一個節點
                GroupComponent child = getTree(rel.getChildCode());
                group.getList().add(child);
            }
            return group;
        }
    }
}
GroupComponent
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;
    }

    /*
     * 列印樹形層級結構
     */
    protected String printTreeStr(int i) {
        // 需要列印的欄位
        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();
            // 遞回進行遍歷
            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();
    }

}
Group
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) {
        // 關鍵欄位
        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();
    }

}
LeafGroup
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;
       }        
    }

}
GroupIterator
public class NullIterator implements Iterator<GroupComponent> {
   
    public GroupComponent next() {
        return null;
    }
  
    public boolean hasNext() {
        return false;
    }
   
    
}
NullIterator

 

測驗程式,遍歷樹形結構、列印樹形結構,

 @Test
    public void Test() {

        // 使用外部迭代器遍歷
        GroupComponent tree = Group.getTree("hotel");

        Iterator<GroupComponent> iterator = tree.createIterator();

        while (iterator.hasNext()) {
            GroupComponent next = iterator.next();
            // TODO 遍歷操作內容

        }

        System.out.println("----列印樹形結構-----");
        
        // 列印樹形結構
        System.err.println(GroupComponent.getTree("hotel").printTreeStr());

    }

 

本文來自博客園,作者:wanglifeng,轉載請注明原文鏈接:https://www.cnblogs.com/wanglifeng717/p/16363485.html

 

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/498980.html

標籤:設計模式

上一篇:優惠券的工廠與策略模式實作方案

下一篇:多系統對接的適配與包裝模式應用

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more