程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> Java設計模式——迭代器模式解析

Java設計模式——迭代器模式解析

編輯:JAVA綜合教程

Java設計模式——迭代器模式解析


概述

網上大部分人說迭代模式的時候,總是以某一種可遍歷的對象為例進行介紹。這是可行的,這也是迭代模式的基本原型。當我看到《Head Frist設計模式》中迭代模式的時候,感覺要是能從另一個角度來說明,可能更能夠體現迭代模式的威力所在。

本文介紹的這種迭代模式,倒是更像是適配器-迭代器模式。希望於你有益~ 

模式說明

網上大多數關於迭代器模式的文章,討論都是建立在一個List或是其他可迭代對象之上的。這樣有一個問題,因為都是可迭代的對象,在迭代的過程中我們無法深入了解到迭代器模式能夠為我們解決什麼樣的問題。下面有一個實例,通過這個實例可能可以說明迭代器模式的威力。

1.實例背景

有兩家餐廳A和B,餐廳A是一家早餐餐廳店,而餐廳B是一家午餐餐廳店。

現在兩個餐廳的大Boss決定將兩家餐廳進行合並。在餐廳A中,菜單的邏輯實現是基於ArrayList的,而餐廳B的菜單邏輯實現則是基於數組的。如果去修改任何一家餐廳的菜單實現,都可能會引發一些不必要的修改,且這種修改可能還會導致不必要的Bug,所以A和B都不願意去修改菜單的原始實現。

現在的需求是,在不改變兩家餐廳對菜單的實現上,再方便地對菜單進行遍歷。

-- 摘自《Head Frist設計模式》

2.思路分析

這個有什麼難的?ArrayList和數組都是可循環遍歷的對象,那麼我們不是可以依次對這兩個數組進行循環遍歷麼?

不可否認,這是一種最為樸素的實現邏輯,而且易懂。可是,這種方式真的是好的麼?如果現在有100家餐廳呢?我們希望的是能夠更方便、更優雅地進行遍歷菜單,我們希望在後期的項目中,代碼的維護性更高,而不是一直“爛”下去。

我們想如果我們的ArrayList和數組可以有一個公共的接口,那麼我們就可以通過這個公共的接口進行迭代,這樣一來代碼的復用性豈不是更高了麼?可是,如何找到這樣的一個接口呢?在學習《Effective Java》這本神書的“類和接口”一單時,就了解到我們的程序中,復合優於繼承。所以,這裡我們可以將ArrayList和數組分別組合到不同的菜單中去,這樣對菜單的遍歷就是對ArrayList或是數組的遍歷。

因為ArrayList自身就包含了迭代器,所以這裡我們不需要為ArrayList創建迭代器。而在數組中則沒有這樣的迭代邏輯,所以我們要為數組額外創建迭代器。

 

3.類圖

根據上面的分析,我們可以畫出如下類圖:

\

圖-1 迭代器模式類圖

4.邏輯實現

(1)公共接口編寫

在類圖中的第一個位置就留給了Menu這個接口了,添加此接口的目的在於提高代碼的可復用性。這一點在第(4)點迭代邏輯中會有所體現。公共接口代碼如下:

 

public interface Menu {
    public Iterator createIterator();
}

 

(2)迭代器的創建

在上面的類圖中我們可以找到BreakfastMenu和LunchMenu兩個菜單類,它們都是實現了Menu接口的。可是,因為它們包含了不同的容器對象(BreakfastMenu包含了ArrayList,LunchMenu包含了數組),所以在創建迭代器的時候就會有所不同。

先來看看BreakfastMenu創建迭代器的邏輯代碼吧,如下:

 

@Override
    public Iterator createIterator() {
        return menuItems.iterator();
    }
因為ArrayList自身就包含了迭代器的實現,所以這裡就可以直接返回ArrayList的迭代器。而數組沒有迭代器的實現部分,所以與上面的創建方式會有所不同,如下:

 

 

@Override
    public Iterator createIterator() {
        return new LunchIterator(menuItems);
    }

 

(3)自定義迭代器

由於數組本身不具備迭代的功能,所以我們就需要對其進行擴展。可是,如果想要“迭代”數組,其根本實現還是要依賴於數組的循環遍歷。因為數組只有這一種方式可以依次提取元素。在迭代器中有兩個核心方法:hasNext()和next()。所以,我們就利用這兩個方法變相實現對數組的迭代。代碼如下:

 

public class LunchIterator implements Iterator {

    private MenuItem[] menuItems = null;
    private int position = 0;
    
    public LunchIterator(MenuItem[] _menuItems) {
        this.menuItems = _menuItems;
    }
    
    @Override
    public boolean hasNext() {
        if (menuItems == null) {
            return false;
        }
        
        return position < menuItems.length;
    }

    @Override
    public MenuItem next() {
        MenuItem menuItem = menuItems[position];
        position++;
        return menuItem;
    }
}
這裡有一個額外定義的變量position,它是用來進行元素索引的,我們需要通過此變量提取元素,和判別迭代完成。

 

(4)迭代邏輯

這裡說的迭代邏輯是針對迭代器之外,客戶端的實現邏輯。假定我們有一個女服務員,她可以打印出客戶所需要的菜單,而不用關心此菜單的實現方式。

 

public class Waitress {

    private Iterator iterator = null;
    private Menu menu = null;
    
    public Waitress(Menu _menu) {
        this.menu = _menu;
    }
    
    public void printMenu() {
        System.out.println("\n菜單:");
        iterator = menu.createIterator();
        do {
            System.out.println(iterator.next());
        } while (iterator.hasNext());
    }
}

 

Ref

《Head Frist設計模式》《23種Java設計模式》

 

Github源碼下載

https://github.com/William-Hai/DesignPattern-Iterator

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved