16.java設計模式之迭代器模式

xiaokantianse發表於2020-12-02

基本需求:

  • 展示一個學校的結構,比如一個學校下面有多個學院,學院下面有多個系,對其節點主要是遍歷,與組合模式略有不同

傳統方案:

  • 學校<-學院<-系 依次繼承
  • 這種方式,在一個頁面中展示出學校的院系組成,一個學校有多個學院,一個學院有多個系,因此這種方案,不能很好實現的遍歷的操作,並且他們之間也沒有繼承關係,使用繼承並不合適

基本介紹:

  • 迭代器模式(Iterator)是常用的設計模式,屬於行為型模式,這種模式用於順序訪問集合物件的元素,不需要知道集合物件的底層表示

  • 如果我們的集合元素是用不同的方式實現的,有陣列,還有java的集合類,或者還有其他方式,當客戶端要遍歷這些集合元素的時候就要使用多種遍歷方式,而且還會暴露元素的內部結構,可以考慮使用迭代器模式解決

  • 迭代器模式提供一種遍歷集合元素的統一介面,用一致的方法遍歷集合元素,不需要知道集合物件的底層表示,即:不暴露其內部的結構

  • 把在元素之間遊走的責任交給迭代器,而不是聚合物件

  • 由於迭代器模式將儲存資料和遍歷資料的職責分離,增加新的聚合類需要對應增加新的迭代器類,類的個數成對增加,這在一定程度上增加了系統的複雜性

  • UML類圖(原理)

    • 說明
      • Iterator:迭代器介面,直接使用JDK提供的即可提供,含有hasNext, next, remove
      • ConcreteIterator:具體的迭代器類,進行元素迭代,其內部元素的以不同的方式進行儲存,例如陣列、list等
      • Aggregate:一個統一的聚合介面,將客戶端和具體聚合解耦,進行元素的儲存
      • ConcreteAggreage:具體的聚合持有物件集合,並提供一個方法,返回一個迭代器,該迭代器可以正確遍歷集合,和ConcreteIterator一一對應
      • Element:集合內部所儲存的元素
      • 實際情況中一般將ConcreteIterator作為內部類放入ConcreteAggreage類中,直接省去了元素集合elementes的傳遞
  • UML類圖(案例)

    • 說明
      • OutputImpl:用於輸出資訊的輔助類
  • 程式碼實現

    • 迭代器類不作為持有迭代集合類的內部類

      • @Data
        @AllArgsConstructor
        public class Department {
        
           // 迭代器內部元素
        
           private String name;
        
           private String description;
        
        }
        
      • public class ComputerCollegeIterator implements Iterator {
        
           // 計算機學院迭代器,元素使用陣列儲存 一般會將迭代器實現類作為需要迭代物件的內部類
        
           private Department[] departments;
        
           // 當前位置指標
           private int index = 0;
        
           public ComputerCollegeIterator(Department[] departments) {
               this.departments = departments;
           }
        
           // 判斷是否有下一個元素
           @Override
           public boolean hasNext() {
               return !(this.index >= this.departments.length);
           }
        
           // 返回下一個元素
           @Override
           public Department next() {
               return this.departments[this.index++];
           }
        
           @Override
           public void remove() {
               // 移除方法空實現
           }
        
        }
        
      • public class InfoCollegeIterator implements Iterator {
        
           // 資訊工程學院迭代器,元素使用List集合儲存 一般會將迭代器實現類作為需要迭代物件的內部類
        
           private List<Department> departments;
        
           // 當前位置指標
           private int index = 0;
        
           public InfoCollegeIterator(List<Department> departments) {
               this.departments = departments;
           }
        
           // 判斷是否有下一個元素
           @Override
           public boolean hasNext() {
               return !(this.index >= this.departments.size());
           }
        
           // 返回下一個元素
           @Override
           public Department next() {
               return this.departments.get(this.index++);
           }
        
           @Override
           public void remove() {
               // 移除方法空實現
           }
        
        }
        
      • public interface College {
        
           // 學院介面
        
           // 獲取學院名稱
           String getName();
        
           // 給學院內部新增系
           void addDepartment(String name, String description);
        
           // 獲取該學院所對應的迭代器
           Iterator createIterator();
        
        }
        
        // 實現類一 計算機學院
        class ComputerCollege implements College {
        
           // 儲存內部元素的集合,用於獲取迭代器
           private Department[] departments;
        
           // 當前元素位置指標
           private int index;
        
           public ComputerCollege() {
               this.departments = new Department[5];
               this.index = 0;
               addDepartment("Java專業", "Java專業 ");
               addDepartment("PHP專業", "PHP專業 ");
               addDepartment("大資料專業", "大資料專業");
           }
        
           @Override
           public String getName() {
               return "計算機學院";
           }
        
           @Override
           public void addDepartment(String name, String description) {
               Department department = new Department(name, description);
               this.departments[this.index++] = department;
           }
        
           @Override
           public Iterator createIterator() {
               return new ComputerCollegeIterator(this.departments);
           }
        
        }
        
        // 實現類二 資訊工程學院
        class InfoCollege implements College {
        
           // 儲存內部元素的集合,用於獲取迭代器
           private List<Department> departments;
        
           public InfoCollege() {
               this.departments = new ArrayList<Department>();
               addDepartment("資訊保安專業", "資訊保安專業");
               addDepartment("網路安全專業", "網路安全專業");
               addDepartment("伺服器安全專業", "伺服器安全專業");
           }
        
           @Override
           public String getName() {
               return "資訊工程學院";
           }
        
           @Override
           public void addDepartment(String name, String description) {
               this.departments.add(new Department(name, description));
           }
        
           @Override
           public Iterator createIterator() {
               return new InfoCollegeIterator(this.departments);
           }
        
        }
        
      • public class OutputImpl {
        
           // 輸出迭代器元素內部的實現類
        
           private List<College> colleges;
        
           public OutputImpl(List<College> colleges) {
               this.colleges = colleges;
           }
        
           public void printCollege() {
               // 獲取List集合內部的迭代器
               Iterator<College> iterator = colleges.iterator();
               while (iterator.hasNext()) {
                   College college = iterator.next();
                   System.out.println("======" + college.getName() + "======");
                   // 獲取學院內部系的迭代器進行迭代輸出 而不需要知道元素再內部以什麼形式的集合存在,統一了遍歷方式
                   printDepartment(college.createIterator());
               }
           }
        
           private void printDepartment(Iterator iterator) {
               while (iterator.hasNext()) {
                   Department department = (Department) iterator.next();
                   if (null != department) {
                       System.out.println(department.getName() + "-----" + department.getDescription());
                   }
               }
           }
           
        }
        
        
      • public class Client {
           public static void main(String[] args) {
               // 建立學院的集合
               List<College> colleges = new ArrayList<College>();
               colleges.add(new ComputerCollege());
               colleges.add(new InfoCollege());
               // 建立輸出類 並迭代輸出學院及其下面的系
               OutputImpl output = new OutputImpl(colleges);
               output.printCollege();
           }
        }
        
    • 迭代器類作為持有迭代集合類的內部類

      • // 實現類一 計算機學院
        public class ComputerCollege implements College {
        
           // 儲存內部元素的集合,用於獲取迭代器
           private Department[] departments;
        
           // 當前元素位置指標
           private int index;
        
           public ComputerCollege() {
               this.departments = new Department[5];
               this.index = 0;
               addDepartment("Java專業", "Java專業 ");
               addDepartment("PHP專業", "PHP專業 ");
               addDepartment("大資料專業", "大資料專業");
           }
        
           @Override
           public String getName() {
               return "計算機學院";
           }
        
           @Override
           public void addDepartment(String name, String description) {
               Department department = new Department(name, description);
               this.departments[this.index++] = department;
           }
        
           @Override
           public Iterator createIterator() {
               return new ComputerCollegeIterator();
           }
        
           // 迭代器類作為持有迭代集合類的內部類
           private class ComputerCollegeIterator implements Iterator {
        
               // 計算機學院迭代器,元素使用陣列儲存 一般會將迭代器實現類作為需要迭代物件的內部類
        
               // 當前位置指標
               private int index = 0;
        
               // 判斷是否有下一個元素 直接使用上層類的元素集合即可
               @Override
               public boolean hasNext() {
                   return !(this.index >= ComputerCollege.this.departments.length);
               }
        
               // 返回下一個元素 直接使用上層類的元素集合即可
               @Override
               public Department next() {
                   return ComputerCollege.this.departments[this.index++];
               }
        
               @Override
               public void remove() {
                   // 移除方法空實現
               }
        
           }
        
        }
        
      • // 實現類二 資訊工程學院
        public class InfoCollege implements College {
        
           // 儲存內部元素的集合,用於獲取迭代器
           private List<Department> departments;
        
           public InfoCollege() {
               this.departments = new ArrayList<Department>();
               addDepartment("資訊保安專業", "資訊保安專業");
               addDepartment("網路安全專業", "網路安全專業");
               addDepartment("伺服器安全專業", "伺服器安全專業");
           }
        
           @Override
           public String getName() {
               return "資訊工程學院";
           }
        
           @Override
           public void addDepartment(String name, String description) {
               this.departments.add(new Department(name, description));
           }
        
           @Override
           public Iterator createIterator() {
               return new InfoCollegeIterator();
           }
        
           // 迭代器類作為持有迭代集合類的內部類
           private class InfoCollegeIterator implements Iterator {
        
               // 資訊工程學院迭代器,元素使用List集合儲存 一般會將迭代器實現類作為需要迭代物件的內部類
        
               // 當前位置指標
               private int index = 0;
        
               // 判斷是否有下一個元素 直接使用上層類的元素集合即可
               @Override
               public boolean hasNext() {
                   return !(this.index >= InfoCollege.this.departments.size());
               }
        
               // 返回下一個元素 直接使用上層類的元素集合即可
               @Override
               public Department next() {
                   return InfoCollege.this.departments.get(this.index++);
               }
        
               @Override
               public void remove() {
                   // 移除方法空實現
               }
        
           }
        
        }
        

jdk原始碼:

  • 在jdk的ArrayList原始碼中就使用到了迭代器模式

  • UML類圖

    • 說明

      • List就是充當了聚合介面,含有一個iterator()方法,返回一個迭代器物件

      • ArrayList是實現聚合介面List的子類,實現了iterator()

      • ArrayList內部的elementData屬性就是存放元素的集合,是一個陣列Object[]

      • Itr充當具體實現迭代器Iterator的類,作為ArrayList內部類

      • Iterator介面JDk提供

      • public class ArrayList<E> extends AbstractList<E>
               implements List<E>, RandomAccess, Cloneable, java.io.Serializable
        {
           // 儲存元素的集合
           transient Object[] elementData;
           
           // 實現獲取迭代器方法
           public Iterator<E> iterator() {
               return new Itr();
           }
        
           /**
            * An optimized version of AbstractList.Itr
            */
           // 作為ArrayList內部類 實現迭代器Iterator
           private class Itr implements Iterator<E> {
              ......
           }
        }
        
        

注意事項:

  • 提供一個統一的方法遍歷物件,客戶不用再考慮聚合的型別,使用一種方法就可以遍歷物件了
  • 隱藏了聚合的內部結構,客戶端要遍歷聚合的時候只能取到迭代器,而不會知道聚合的具體組成
  • 提供了一種設計思想,就是一個類應該只有一個引起變化的原因(叫做單一責任原則)。在聚合類中,我們把迭代器分開,就是要把管理物件集合和遍歷物件集合的責任分開,這樣一來集合改變的話,隻影響到聚合物件。而如果遍歷方式改變的話,隻影響到了迭代器
  • 當要展示一組相似物件,或者遍歷一組相同物件時使用, 適合使用迭代器模式
  • 每個聚合物件都要一個迭代器,會生成多個迭代器不好管理類

相關文章