設計模式 | 迭代器模式(詳解)

迭代器模式

前言
很早之前,我們的電視調節頻道是需要用電視上的按鈕去控制的,那時並沒有遙控器,如果我們想要調臺,只能一次又一次的擰按鈕。

在這裏插入圖片描述
越來越高級的電視機相繼出現,現在的電話機,我們有了電視遙控器,我們使用電視遙控器來調臺,這個時候,無需直接操作電視。
在這裏插入圖片描述在這裏插入圖片描述
我們可以將電視機看成一個存儲電視頻道的集合對象,通過遙控器可以對電視機中的電視頻道集合進行操作,如返回上一個頻道、跳轉到下一個頻道或者跳轉至指定的頻道。遙控器爲我們操作電視頻道帶來很大的方便,用戶並不需要知道這些頻道到底如何存儲在電視機中。

具體案例:
編寫程序展示一個學校院系結構:需求是這樣,要在一個頁面中展示出學校的院系 組成,一個學校有多個學院,一個學院有多個系
分析:

每一個學院都有添加系的功能,如果我們將遍歷的方法hasNext() next()等寫入。這將導致聚合類的職責過重,它既負責存儲和管理數據,又負責遍歷數據,違反了“單一職責原則”,由於聚合類非常龐大,實現代碼過長,還將給測試和維護增加難度。

那麼這個時候,我們也許會這樣想,因爲有多個學院,我們不妨將學院封裝爲接口,但是在這個接口中充斥着大量方法,不利於子類實現,違反了“接口隔離原則”。

解決方案:

解決方案之一就是將聚合類中負責遍歷數據的方法提取出來,封裝到專門的類中,實現數據存儲和數據遍歷分離,無須暴露聚合類的內部屬性即可對其進行操作,而這正是迭代器模式的意圖所在。

基本介紹
  1. 迭代器模式(Iterator Pattern)是常用的設計模式,屬於行爲型模式
  2. 如果我們的集合元素是用不同的方式實現的,有數組,還有java的集合類,
    或者還有其他方式,當客戶端要遍歷這些集合元素的時候就要使用多種遍歷
    方式,而且還會暴露元素的內部結構,可以考慮使用迭代器模式解決。
  3. 迭代器模式,提供一種遍歷集合元素的統一接口,用一致的方法遍歷集合元素,
    不需要知道集合對象的底層表示,即:不暴露其內部的結構。
原理類圖:

在這裏插入圖片描述

角色分析:
  1. Iterator (抽象迭代器): 迭代器接口,是系統提供,含義 hasNext, next, remove
  2. ConcreteIterator (具體迭代器): 具體的迭代器類,管理迭代 在具體迭代器中通過遊標來記錄在聚合對象中所處的當前位置,在具體實現時,遊標通常是一個表示位置的非負整數。
  3. Aggregate (抽象聚合類):一個統一的聚合接口, 將客戶端和具體聚合解耦
  4. ConcreteAggreage (具體聚合類): 具體的聚合持有對象集合, 並提供一個方法,返回一個
代碼實例:

聚合類:

學院接口:

/**
 * 學院
 *
 * @author 孫一鳴 on 2020/2/17
 */
public interface College {

    public String getName();
    //增加系的方法
    public void addDepartment (String name,String des);

    //換回一個迭代器,遍歷
    public Iterator createIterator();

}

計算機學院:


/**
 * 計算機學院
 *
 * @author 孫一鳴 on 2020/2/17
 */
public class ComputerCollege implements College
{
    Department[] departments;
    int numOfDepartment = 0;//保存當前數組對象個數

    public ComputerCollege() {
        departments = new Department[5];//計算機學院有5個系
        addDepartment("Java","JAVA牛逼");
        addDepartment("Php","經典");
        addDepartment("C#","還好");
        addDepartment("Python","智能");
        addDepartment("GO","牛");

    }

    @Override
    public String getName() {
        return "計算機學院";
    }

    //給計算機學院添加系
    @Override
    public void addDepartment(String name,String des) {
        Department department = new Department(name,des);
        departments[numOfDepartment] = department;
        numOfDepartment += 1;
    }

    @Override
    public Iterator createIterator() {
        return new ComputerCollegeIterator(departments);
    }
}

信息學院


/**
 * 信息學院
 *
 * @author 孫一鳴 on 2020/2/17
 */
public class InfoCollege implements College
{
    List<Department> departments;
   // int numOfDepartment = 0;//保存當前數組對象個數

    public InfoCollege() {
        departments = new ArrayList<Department>();
        //計算機學院有5個系
        addDepartment("信息安全","JAVA牛逼");
        addDepartment("網絡安全","經典");
        addDepartment("服務器安全","還好");
        addDepartment("數據庫安全","智能");
    }

    @Override
    public String getName() {
        return "計算機學院";
    }

    //給計算機學院添加系
    @Override
    public void addDepartment(String name,String des) {
        Department department = new Department(name,des);
       departments.add(department);
        //numOfDepartment += 1;
    }

    @Override
    public Iterator createIterator() {
        return new InfoCollegeIterator(departments);
    }
}

學院下面的系:


/**
 * 系
 *學校 --學院 -- 系
 * @author 孫一鳴 on 2020/2/17
 */
public class Department {
     private  String name;
     private  String des;

    public Department(String name, String des) {
        this.name = name;
        this.des = des;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDes() {
        return des;
    }

    public void setDes(String des) {
        this.des = des;
    }
}

迭代器類:
計算機學院迭代器


/**
 * @author 孫一鳴 on 2020/2/17
 * ComputerCollegeIterator: 計算機學院迭代器,
 * 遍歷計算機學院下的系
 */
public class ComputerCollegeIterator implements Iterator {

    /*
    * 這裏需要知道 Department 以怎樣的方式存放
    *
    * */

    Department[] departments;
    int position = 0;//遍歷的位置

    public ComputerCollegeIterator(Department[] departments) {
        this.departments = departments;
    }

    @Override
    public boolean hasNext() {
        if (position >= departments.length || departments[position] ==null)
        {
            return false;
        }else {
            return  true;
        }
    }

    @Override
    public Object next() {
        Department department =departments[position];
        position +=1;
        return department;
    }

    @Override
    public void remove() {

    }
}

信息學院迭代器:


/**
 * @author 孫一鳴 on 2020/2/17
 * ComputerCollegeIterator: 信息學院迭代器,
 * 遍歷信息學院下的系
 */
public class InfoCollegeIterator implements Iterator {

    /*
    * 這裏需要知道 Department 以怎樣的方式存放
    *
    * */

    List<Department> departments;
    int position = -1;//索引

    public InfoCollegeIterator( List<Department> departments) {
        this.departments = departments;
    }

    @Override
    public boolean hasNext() {
        if (position >= departments.size()-1 )
        {
            return false;
        }else {
            position +=1;
            return  true;
        }
    }

    @Override
    public Object next() {

        return departments.get(position);
    }

    @Override
    public void remove() {

    }
}

輸出信息類:


/**
 * @author 孫一鳴 on 2020/2/17
 * 輸出信息類
 */
public class OutPutClass {
    List<College> colleges;

    public OutPutClass(List<College> colleges) {
        this.colleges = colleges;
    }

    //遍歷單個學院取出系
    public void printDepartment(Iterator iterator) {
        while (iterator.hasNext()) {
            Department department = (Department) iterator.next();
            System.out.println("department.getName() = " + department.getName());
        }
    }

    //遍歷學院集合 輸出所有學院
    public void printCollege() {
        //此時遍歷不用傳入 迭代器
        //學院使用List集合 已經實現Iterator
        Iterator<College> iterator = colleges.iterator();
        while(iterator.hasNext()){
            //取出一個學院
            College college = iterator.next();
            System.out.println("========="+college.getName()+"====");
            printDepartment(college.createIterator());
        }
    }
}

測試類:


/**
 * @author 孫一鳴 on 2020/2/17
 */
public class Client {
    public static void main(String[] args) {
        List<College> colleges = new ArrayList<College>();
        College computerCollege = new ComputerCollege();
        College infocollege = new InfoCollege();
        colleges.add(computerCollege);
        colleges.add(infocollege);

        OutPutClass outPutClass = new OutPutClass(colleges);
        outPutClass.printCollege();
    }
}

結果截圖:

在這裏插入圖片描述

代碼分析:

如果需要增加一個新的具體聚合類,只需增加一個新的聚合子類和一個新的具體迭代器類即可,原有類庫代碼無須修改,符合“開閉原則”;

如果需要爲聚合類更換一個迭代器,只需要增加一個新的具體迭代器類作爲抽象迭代器類的子類,重新實現遍歷方法,原有迭代器代碼無須修改,也符合“開閉原則”;

但是如果要在迭代器中增加新的方法,則需要修改抽象迭代器源代碼,這將違背“開閉原則”。

迭代器模式在JDK-ArrayList集合應用的源碼分析

在這裏插入圖片描述
角色分析說明

  • 內部類Itr 充當具體實現迭代器Iterator 的類, 作爲ArrayList 內部類
  • List 就是充當了聚合接口,含有一個iterator() 方法,返回一個迭代器對象
  • ArrayList 是實現聚合接口List 的子類,實現了iterator()
  • Iterator 接口系統提供
  • 迭代器模式解決了 不同集合(ArrayList ,LinkedList) 統一遍歷問題

優點

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

缺點
每個聚合對象都要一個迭代器,會生成多個迭代器不好管理類

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章