《一天一模式》— 迭代器模式

1、迭代器模式的概念

供一種方法順序訪問一個聚合對象中的各類元素,而又不暴露該對象的內部表示。 java

2、何時使用迭代器模式

迭代器模式使用的場景很明確,那就是封裝遍歷數組

當業務要對你的對象中的某一數據結構進行遍歷,一般有兩種作法:安全

  • 把數據結構返回給調用者,讓他去遍歷;
  • 引用迭代器模式,封裝遍歷;

下面具體來看看怎麼作。bash

3、怎麼使用迭代器模式

經過一個業務場景進行說明,仍是使用Java代碼作演示。數據結構

假設有一個兩種菜單(系統菜單和業務菜單),需求是須要遍歷這兩種菜單。先來看看不使用迭代器模式有什麼弊端。ide

3.1 不適用迭代器模式帶來的弊端

加入先開發了業務菜單,數據結構是數組:函數

@Data
public class BusinessMenu {

    private String[] menus = new String[3];

    public BusinessMenu() {
        menus[0] = "業務菜單A";
        menus[1] = "業務菜單B";
        menus[2] = "業務菜單C";
    }

}

而後開發了系統菜單,這是數據結構換成了集合:工具

@Data
public class SystemMenu {

    private List<String> menus = new ArrayList<>();

    public SystemMenu() {
        menus.add("系統菜單1");
        menus.add("系統菜單2");
        menus.add("系統菜單3");
    }

}

而後實現遍歷的客戶端以下:spa

public class Client {

    public static void main(String[] args) {
        SystemMenu menus = new SystemMenu();
        List<String> mlist = menus.getMenus();
        printSystemMenu(mlist);
        System.out.println();
        BusinessMenu buttons = new BusinessMenu();
        String[] blist = buttons.getMenus();
        printBusinessMenu(blist);
    }

    public static void printSystemMenu(List<String> mlist) {
        for (int i = 0; i < mlist.size(); i++) {
            System.out.println(mlist.get(i));
        }
    }

    public static void printBusinessMenu(String[] blist) {
        for (int i = 0; i < blist.length; i++) {
            System.out.println(blist[i]);
        }
    }

}

這種狀況就是第二節說到的,把數據結構返回給調用者,讓他去實現遍歷,說的更確切一些,是讓他去操做數據結構進行遍歷。設計

這種作法有兩個弊端:

  • 數據安全:若是沒有很好的控制數據結構的訪問權限,不能限制調用者,有可能會對數據形成破壞;
  • 擴展性低:上面的代碼寫了兩個函數,printSystemMenu和printBusinessMenu,由於內部數據結構不一樣,因此實現不一樣,若是再有其餘的Menu對象,內部的數據結構不是數據或者List,那麼又要添加新的遍歷方法,這不復合開閉原則,也是擴展性低的結症;

如何使用迭代器模式解決這個問題呢?其實Java內部提供了迭代器接口,咱們也能夠本身建立一個迭代器接口,具體以下。

3.2 使用迭代器模式解決弊端

我準備直接使用Java提供的迭代器接口實現,先來看看類圖和代碼:

代碼以下:

// 系統菜單,實現了迭代器接口
public class SystemMenu implements Iterator<String> {

    // 私有化數據結構
    private List<String> menus = new ArrayList<>();
    // 私有化的索引
    private int index;

    public SystemMenu() {
        menus.add("系統菜單1");
        menus.add("系統菜單2");
        menus.add("系統菜單3");
        index = 0;
    }

    @Override
    public boolean hasNext() {
        // 判斷集合是否還有元素
        return index < menus.size();
    }

    @Override
    public String next() {
        // 返回集合的元素
        String name = menus.get(index);
        // 索引+1
        index++;
        return name;
    }
}
// 業務菜單,實現了迭代器接口
public class BusinessMenu implements Iterator<String> {

    // 私有化數據結構
    private String[] menus = new String[3];
    // 私有化的索引
    private int index;

    public BusinessMenu() {
        menus[0] = "業務菜單A";
        menus[1] = "業務菜單B";
        menus[2] = "業務菜單C";
        index = 0;
    }

    @Override
    public boolean hasNext() {
        // 判斷數組是否還有元素
        return index < menus.length;
    }

    @Override
    public String next() {
        // 返回數組中的元素
        String name = menus[index];
        // 索引+1
        index++;
        return name;
    }
}
public class Client {

    public static void main(String[] args) {
        printMenu(new SystemMenu());
        System.out.println();
        printMenu(new BusinessMenu());
    }

    public static void printMenu(Iterator<String> iterator) {
        // 使用迭代器,循環輸出
        while(iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }

}
輸出:
系統菜單1
系統菜單2
系統菜單3

業務菜單A
業務菜單B
業務菜單C

上面就是迭代器模式,很簡單,咱們在平常開發中常常會使用到,許多的工具類都會提供迭代器讓咱們進行遍歷。

可是仍是說說如何解決了弊端:

  • 數據安全:將數據結構封裝到了對象內部,外部沒法對其進行操做;
  • 封裝遍歷:實現了Java提供的迭代器接口(泛型的),將迭代的步驟封裝成hasNext和next兩個函數;

4、總結

迭代器模式提高了類的內聚性!

類的每一個責任都有改變的潛在區域。超過一個責任,意味着超過一個改變區域。

這個原則告訴咱們,儘可能讓每個類保持單一責任。

內聚(Cohesion)這個術語,它用來度量一個類或者模塊是否緊密地達到單一目的或責任。

當一個模塊或一個類被設計成只支持一組相關的功能時,咱們說它具備高內聚;反之,當被設計成支持一組不相關的功能時,咱們說它具備低內聚。

內聚是一個比單一職責更廣泛的概念,但二者其實關係是很密切的。遵照這個原則的類更容易有很高的凝聚力,並且比揹負許多職責的低內聚類更容易維護。

以上就是我對迭代器模式的一些理解,有不足之處請你們指出,謝謝。

相關文章
相關標籤/搜索