乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      重學(xué) Java 設(shè)計模式:實戰(zhàn)迭代器模式「模擬公司組織架構(gòu)樹結(jié)構(gòu)關(guān)系,深度迭代遍歷人員信息輸出場景」

       小傅哥 2021-12-13


      作者:小傅哥
      博客:https:// - 原創(chuàng)系列專題文章

      沉淀、分享、成長,讓自己和他人都能有所收獲!😄

      一、前言

      相信相信的力量!

      從懵懂的少年,到拿起鍵盤,可以寫一個HelloWorld。多數(shù)人在這并不會感覺有多難,也不會認為做不出來。因為這樣的例子,有老師的指導(dǎo)、有書本的例子、有前人的經(jīng)驗。但隨著你的開發(fā)時間越來越長,要解決更復(fù)雜的問題或者技術(shù)創(chuàng)新,因此在網(wǎng)上搜了幾天幾夜都沒有答案,這個時候是否想過放棄,還是一直堅持不斷的嘗試一點點完成自己心里要的結(jié)果。往往這種沒有前車之鑒需要自己解決問題的時候,可能真的會折磨到要崩潰,但你要愿意執(zhí)著、愿意倔強,愿意選擇相信相信的力量,就一定能解決。哪怕解決不了,也可以在這條路上摸索出其他更多的收獲,為后續(xù)前進的道路填充好墊腳石。

      時間緊是寫垃圾代碼的理由?

      擰螺絲?Ctrl+C、Ctrl+V?貼膏藥一樣寫代碼?沒有辦法,沒有時間,往往真的是借口,胸中沒用筆墨,才只能湊合。難道一定是好好寫代碼就浪費時間,拼湊CRUD就快嗎,根本不可能的。因為不會,沒用實操過,很少架構(gòu)出全場景的設(shè)計,才很難寫出優(yōu)良的代碼。多增強自身的編碼(武術(shù))修為,在各種編碼場景中讓自己變得老練,才好應(yīng)對緊急情況下的需求開發(fā)和人員安排。就像韓信一樣有謀有略,才能執(zhí)掌百萬雄兵。

      不要只是做個工具人!

      因為日常的編寫簡單業(yè)務(wù)需求,導(dǎo)致自己像個工具人一樣,日久天長的也就很少去深入學(xué)習(xí)更多技術(shù)棧。看見有工具、有組件、有框架,拿來就用用,反正沒什么體量也不會出什么問題。但如果你想要更多的收入,哪怕是重復(fù)的造輪子,你也要去嘗試造一個,就算不用到生產(chǎn),自己玩玩總可以吧。有些事情只有自己經(jīng)歷過,才能有最深的感觸,參與過實踐過,才好總結(jié)點評學(xué)習(xí)。

      二、開發(fā)環(huán)境

      1. JDK 1.8
      2. Idea + Maven
      3. 涉及工程一個,可以通過關(guān)注公眾號bugstack蟲洞棧,回復(fù)源碼下載獲取(打開獲取的鏈接,找到序號18)
      工程描述
      itstack-demo-design-15-00開發(fā)樹形組織架構(gòu)關(guān)系迭代器

      三、迭代器模式介紹

      迭代器模式,圖片來自 refactoringguru.cn

      迭代器模式,常見的就是我們?nèi)粘J褂玫?code>iterator遍歷。雖然這個設(shè)計模式在我們的實際業(yè)務(wù)開發(fā)中的場景并不多,但卻幾乎每天都要使用jdk為我們提供的list集合遍歷。另外增強的for循環(huán)雖然是循環(huán)輸出數(shù)據(jù),但是他不是迭代器模式。迭代器模式的特點是實現(xiàn)Iterable接口,通過next的方式獲取集合元素,同時具備對元素的刪除等操作。而增強的for循環(huán)是不可以的。

      這種設(shè)計模式的優(yōu)點是可以讓我們以相同的方式,遍歷不同的數(shù)據(jù)結(jié)構(gòu)元素,這些數(shù)據(jù)結(jié)構(gòu)包括;數(shù)組、鏈表等,而用戶在使用遍歷的時候并不需要去關(guān)心每一種數(shù)據(jù)結(jié)構(gòu)的遍歷處理邏輯,從讓使用變得統(tǒng)一易用。

      四、案例場景模擬

      在本案例中我們模擬迭代遍歷輸出公司中樹形結(jié)構(gòu)的組織架構(gòu)關(guān)系中雇員列表

      大部分公司的組織架構(gòu)都是金字塔結(jié)構(gòu),也就這種樹形結(jié)構(gòu),分為一級、二級、三級等部門,每個組織部門由雇員填充,最終體現(xiàn)出一個整體的樹形組織架構(gòu)關(guān)系。

      一般我們常用的遍歷就是jdk默認提供的方法,對list集合遍歷。但是對于這樣的偏業(yè)務(wù)特性較大的樹形結(jié)構(gòu),如果需要使用到遍歷,那么就可以自己來實現(xiàn)。接下來我們會把這個組織層次關(guān)系通過樹形數(shù)據(jù)結(jié)構(gòu)來實現(xiàn),并完成迭代器功能。

      五、迭代器模式遍歷組織結(jié)構(gòu)

      在實現(xiàn)迭代器模式之前可以先閱讀下javalist方法關(guān)于iterator的實現(xiàn)部分,幾乎所有的迭代器開發(fā)都會按照這個模式來實現(xiàn),這個模式主要分為以下幾塊;

      1. Collection,集合方法部分用于對自定義的數(shù)據(jù)結(jié)構(gòu)添加通用方法;add、remove、iterator等核心方法。
      2. Iterable,提供獲取迭代器,這個接口類會被Collection繼承。
      3. Iterator,提供了兩個方法的定義;hasNextnext,會在具體的數(shù)據(jù)結(jié)構(gòu)中寫實現(xiàn)方式。

      除了這樣通用的迭代器實現(xiàn)方式外,我們的組織關(guān)系結(jié)構(gòu)樹,是由節(jié)點和節(jié)點間的關(guān)系鏈構(gòu)成,所以會比上述的內(nèi)容多一些入?yún)ⅰ?/p>

      1. 工程結(jié)構(gòu)

      itstack-demo-design-15-02
      └── src
          ├── main
          │   └── java
          │       └── org.itstack.demo.design
          │           ├── group
          │           │├── Employee.java
          │           │├── GroupStructure.java
          │           │└── Link.java
          │           └──  lang
          │            ├── Collection.java
          │            ├── Iterable.java
          │            └── Iterator.java
          └── test
              └── java
                  └── org.itstack.demo.design.test
                      └── ApiTest.java
      

      迭代器模式模型結(jié)構(gòu)

      迭代器模式模型結(jié)構(gòu)

      • 以上是我們工程類圖的模型結(jié)構(gòu),左側(cè)是對迭代器的定義,右側(cè)是在數(shù)據(jù)結(jié)構(gòu)中實現(xiàn)迭代器功能。
      • 關(guān)于左側(cè)部分的實現(xiàn)與jdk中的方式是一樣的,所以在學(xué)習(xí)的過程中可以互相參考,也可以自己擴展學(xué)習(xí)。
      • 另外這個遍歷方式一個樹形結(jié)構(gòu)的深度遍歷,為了可以更加讓學(xué)習(xí)的小伙伴容易理解,這里我實現(xiàn)了一種比較簡單的樹形結(jié)構(gòu)深度遍歷方式。后續(xù)讀者也可以把遍歷擴展為橫向遍歷也就是寬度遍歷。

      2. 代碼實現(xiàn)

      2.1 雇員實體類

      /**
       * 雇員
       */
      public class Employee {
      
          private String uId;   // ID
          private String name;  // 姓名
          private String desc;  // 備注
          
          // ...get/set
      }
      
      • 這是一個簡單的雇員類,也就是公司員工的信息類,包括必要的信息;id、姓名、備注。

      2.2 樹節(jié)點鏈路

      /**
       * 樹節(jié)點鏈路
       */
      public class Link {
      
          private String fromId; // 雇員ID
          private String toId;   // 雇員ID    
          
          // ...get/set
      }
      
      • 這個類用于描述結(jié)構(gòu)樹中的各個節(jié)點之間的關(guān)系鏈,也就是A to B、B to C、B to D,以此描述出一套完整的樹組織結(jié)構(gòu)。

      2.3 迭代器定義

      public interface Iterator<E> {
      
          boolean hasNext();
      
          E next();
          
      }
      
      • 這里的這個類和javajdk中提供的是一樣的,這樣也方面后續(xù)讀者可以對照listIterator進行源碼學(xué)習(xí)。
      • 方法描述;hasNext,判斷是否有下一個元素、next,獲取下一個元素。這個在list的遍歷中是經(jīng)常用到的。

      2.4 可迭代接口定義

      public interface Iterable<E> {
      
          Iterator<E> iterator();
      
      }
      
      • 這個接口中提供了上面迭代器的實現(xiàn)Iterator的獲取,也就是后續(xù)在自己的數(shù)據(jù)結(jié)構(gòu)中需要實現(xiàn)迭代器的功能并交給Iterable,由此讓外部調(diào)用方進行獲取使用。

      2.5 集合功能接口定義

      public interface Collection<E, L> extends Iterable<E> {
      
          boolean add(E e);
      
          boolean remove(E e);
      
          boolean addLink(String key, L l);
      
          boolean removeLink(String key);
      
          Iterator<E> iterator();
      
      }
      
      • 這里我們定義集合操作接口;Collection,同時繼承了另外一個接口Iterable的方法iterator()。這樣后續(xù)誰來實現(xiàn)這個接口,就需要實現(xiàn)上述定義的一些基本功能;添加元素、刪除元素、遍歷。
      • 同時你可能注意到這里定義了兩個泛型<E, L>,因為我們的數(shù)據(jù)結(jié)構(gòu)一個是用于添加元素,另外一個是用于添加樹節(jié)點的鏈路關(guān)系。

      2.6 (核心)迭代器功能實現(xiàn)

      public class GroupStructure implements Collection<Employee, Link> {
      
          private String groupId;                                                 // 組織ID,也是一個組織鏈的頭部ID
          private String groupName;                                               // 組織名稱
          private Map<String, Employee> employeeMap = new ConcurrentHashMap<String, Employee>();  // 雇員列表
          private Map<String, List<Link>> linkMap = new ConcurrentHashMap<String, List<Link>>();  // 組織架構(gòu)關(guān)系;id->list
          private Map<String, String> invertedMap = new ConcurrentHashMap<String, String>();       // 反向關(guān)系鏈
      
          public GroupStructure(String groupId, String groupName) {
              this.groupId = groupId;
              this.groupName = groupName;
          }
      
          public boolean add(Employee employee) {
              return null != employeeMap.put(employee.getuId(), employee);
          }
      
          public boolean remove(Employee o) {
              return null != employeeMap.remove(o.getuId());
          }
      
          public boolean addLink(String key, Link link) {
              invertedMap.put(link.getToId(), link.getFromId());
              if (linkMap.containsKey(key)) {
                  return linkMap.get(key).add(link);
              } else {
                  List<Link> links = new LinkedList<Link>();
                  links.add(link);
                  linkMap.put(key, links);
                  return true;
              }
          }
      
          public boolean removeLink(String key) {
              return null != linkMap.remove(key);
          }
      
          public Iterator<Employee> iterator() {
      
              return new Iterator<Employee>() {
      
                  HashMap<String, Integer> keyMap = new HashMap<String, Integer>();
      
                  int totalIdx = 0;
                  private String fromId = groupId;  // 雇員ID,From
                  private String toId = groupId;   // 雇員ID,To
      
                  public boolean hasNext() {
                      return totalIdx < employeeMap.size();
                  }
      
                  public Employee next() {
                      List<Link> links = linkMap.get(toId);
                      int cursorIdx = getCursorIdx(toId);
      
                      // 同級節(jié)點掃描
                      if (null == links) {
                          cursorIdx = getCursorIdx(fromId);
                          links = linkMap.get(fromId);
                      }
      
                      // 上級節(jié)點掃描
                      while (cursorIdx > links.size() - 1) {
                          fromId = invertedMap.get(fromId);
                          cursorIdx = getCursorIdx(fromId);
                          links = linkMap.get(fromId);
                      }
      
                      // 獲取節(jié)點
                      Link link = links.get(cursorIdx);
                      toId = link.getToId();
                      fromId = link.getFromId();
                      totalIdx++;
      
                      // 返回結(jié)果
                      return employeeMap.get(link.getToId());
                  }
                   
                  // 給每個層級定義寬度遍歷進度
                  public int getCursorIdx(String key) {
                      int idx = 0;
                      if (keyMap.containsKey(key)) {
                          idx = keyMap.get(key);
                          keyMap.put(key, ++idx);
                      } else {
                          keyMap.put(key, idx);
                      }
                      return idx;
                  }
              };
          }
      
      }
      
      • 以上的這部分代碼稍微有點長,主要包括了對元素的添加和刪除。另外最重要的是對遍歷的實現(xiàn)new Iterator<Employee>。
      • 添加和刪除元素相對來說比較簡單,使用了兩個map數(shù)組結(jié)構(gòu)進行定義;雇員列表、組織架構(gòu)關(guān)系;id->list。當(dāng)元素添加元素的時候,會分別在不同的方法中向map結(jié)構(gòu)中進行填充指向關(guān)系(A->B),也就構(gòu)建出了我們的樹形組織關(guān)系。

      迭代器實現(xiàn)思路

      1. 這里的樹形結(jié)構(gòu)我們需要做的是深度遍歷,也就是左側(cè)的一直遍歷到最深節(jié)點。
      2. 當(dāng)遍歷到最深節(jié)點后,開始遍歷最深節(jié)點的橫向節(jié)點。
      3. 當(dāng)橫向節(jié)點遍歷完成后則向上尋找橫向節(jié)點,直至樹結(jié)構(gòu)全部遍歷完成。

      3. 測試驗證

      3.1 編寫測試類

      @Test
      public void test_iterator() { 
          // 數(shù)據(jù)填充
          GroupStructure groupStructure = new GroupStructure("1", "小傅哥");  
          
          // 雇員信息
          groupStructure.add(new Employee("2", "花花", "二級部門"));
          groupStructure.add(new Employee("3", "豆包", "二級部門"));
          groupStructure.add(new Employee("4", "蹦蹦", "三級部門"));
          groupStructure.add(new Employee("5", "大燒", "三級部門"));
          groupStructure.add(new Employee("6", "虎哥", "四級部門"));
          groupStructure.add(new Employee("7", "玲姐", "四級部門"));
          groupStructure.add(new Employee("8", "秋雅", "四級部門"));   
          
          // 節(jié)點關(guān)系 1->(1,2) 2->(4,5)
          groupStructure.addLink("1", new Link("1", "2"));
          groupStructure.addLink("1", new Link("1", "3"));
          groupStructure.addLink("2", new Link("2", "4"));
          groupStructure.addLink("2", new Link("2", "5"));
          groupStructure.addLink("5", new Link("5", "6"));
          groupStructure.addLink("5", new Link("5", "7"));
          groupStructure.addLink("5", new Link("5", "8"));       
      
          Iterator<Employee> iterator = groupStructure.iterator();
          while (iterator.hasNext()) {
              Employee employee = iterator.next();
              logger.info("{},雇員 Id:{} Name:{}", employee.getDesc(), employee.getuId(), employee.getName());
          }
      }
      

      3.2 測試結(jié)果

      22:23:37.166 [main] INFO  org.itstack.demo.design.test.ApiTest - 二級部門,雇員 Id:2 Name:花花
      22:23:37.168 [main] INFO  org.itstack.demo.design.test.ApiTest - 三級部門,雇員 Id:4 Name:蹦蹦
      22:23:37.169 [main] INFO  org.itstack.demo.design.test.ApiTest - 三級部門,雇員 Id:5 Name:大燒
      22:23:37.169 [main] INFO  org.itstack.demo.design.test.ApiTest - 四級部門,雇員 Id:6 Name:虎哥
      22:23:37.169 [main] INFO  org.itstack.demo.design.test.ApiTest - 四級部門,雇員 Id:7 Name:玲姐
      22:23:37.169 [main] INFO  org.itstack.demo.design.test.ApiTest - 四級部門,雇員 Id:8 Name:秋雅
      22:23:37.169 [main] INFO  org.itstack.demo.design.test.ApiTest - 二級部門,雇員 Id:3 Name:豆包
      
      Process finished with exit code 0
      
      • 從遍歷的結(jié)果可以看到,我們是順著樹形結(jié)構(gòu)的深度開始遍歷,一直到右側(cè)的節(jié)點3雇員 Id:2、雇員 Id:4...雇員 Id:3

      六、總結(jié)

      • 迭代器的設(shè)計模式從以上的功能實現(xiàn)可以看到,滿足了單一職責(zé)和開閉原則,外界的調(diào)用方也不需要知道任何一個不同的數(shù)據(jù)結(jié)構(gòu)在使用上的遍歷差異??梢苑浅7奖愕臄U展,也讓整個遍歷變得更加干凈整潔。
      • 但從結(jié)構(gòu)的實現(xiàn)上可以看到,迭代器模式的實現(xiàn)過程相對來說是比較負責(zé)的,類的實現(xiàn)上也擴增了需要外部定義的類,使得遍歷與原數(shù)據(jù)結(jié)構(gòu)分開。雖然這是比較麻煩的,但可以看到在使用java的jdk時候,迭代器的模式還是很好用的,可以非常方便擴展和升級。
      • 以上的設(shè)計模式場景實現(xiàn)過程可能對新人有一些不好理解點,包括;迭代器三個和接口的定義、樹形結(jié)構(gòu)的數(shù)據(jù)關(guān)系、樹結(jié)構(gòu)深度遍歷思路。這些都需要反復(fù)實現(xiàn)練習(xí)才能深入的理解,事必躬親,親歷親為,才能讓自己掌握這些知識。

      七、推薦閱讀

      • 1. 重學(xué) Java 設(shè)計模式:實戰(zhàn)工廠方法模式「多種類型商品不同接口,統(tǒng)一發(fā)獎服務(wù)搭建場景」
      • 2. 重學(xué) Java 設(shè)計模式:實戰(zhàn)原型模式「上機考試多套試,每人題目和答案亂序排列場景」
      • 3. 重學(xué) Java 設(shè)計模式:實戰(zhàn)橋接模式「多支付渠道(微信、支付寶)與多支付模式(刷臉、指紋)場景」
      • 4. 重學(xué) Java 設(shè)計模式:實戰(zhàn)組合模式「營銷差異化人群發(fā)券,決策樹引擎搭建場景」
      • 5. 重學(xué) Java 設(shè)計模式:實戰(zhàn)外觀模式「基于SpringBoot開發(fā)門面模式中間件,統(tǒng)一控制接口白名單場景」
      • 6. 重學(xué) Java 設(shè)計模式:實戰(zhàn)享元模式「基于Redis秒殺,提供活動與庫存信息查詢場景」

        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多