天天看點

疊代器模式模式背景模式定義模式結構模式實作LuchMenu建立疊代器使用場景模式優缺點模式總結

很多人認為今天看疊代器模式使用價值遠不如學習價值了,Martin Flower 甚至在在自己的網頁上提出撤銷此模式。當然這種說法也不無道理,因為現在像進階語言如C# 、java 等已經把這個模式做在語言中了。但是這個模式就真的如網上所言沒有實用價值了嗎?我并不認為是這樣的。

    本文将介紹這種模式與其它模式搭配使用 擴充卡-疊代器模式。至于有沒有用評判在你

疊代器模式模式背景模式定義模式結構模式實作LuchMenu建立疊代器使用場景模式優缺點模式總結

 希望于你有益~

模式背景

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

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

    現在的需求是,在不改變兩家餐廳對菜單的實作上,再友善地對菜單進行周遊。

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

模式定義

何謂疊代器模式?所謂疊代器模式就是提供一種方法順序通路一個聚合對象中的各個元素,而不是暴露其内部的表示。在實際的開發過程中,我們可能需要針對不同的需求,可能需要以不同的方式來周遊整個整合對象,但是我們不希望在聚合對象的抽象接口層中充斥着各種不同的便利操作。這個時候我們就需要這樣一種東西,它應該具備如下三個功能:

      1、能夠便利一個聚合對象。

      2、我們不需要了解聚合對象的内部結構。

      3、能夠提供多種不同的周遊方式。

      這三個功能就是疊代器模式需要解決的問題。作為一個功能強大的模式,疊代器模式把在元素之間遊走的責任交給疊代器,而不是聚合對象。這樣做就簡化了聚合的接口和實作,也可以讓聚合更專注在它所應該專注的事情上,這樣做就更加符合單一責任原則。

科普

    聚合對象:

聚合(Cohesion)是一個子產品内部各成分之間相關聯程度的度量。

這裡有多個含義值得考慮。首先,聚合是對一個子產品内部的度量,這也是許多情況下我們把聚合稱之為内聚的原因。第二,這裡出現的子產品是廣義的子產品,它可能是子系統,可能是功能子產品,也可能是功能子產品中的某一個類。從不同的層次看,聚合的程度也會有所不同。至于為什麼不同,後面會有解釋。第三,子產品的成分包括子產品的行為和狀态。要做到高聚合,那麼子產品内部的行為必須要與子產品的内部狀态緊密關聯。通俗來講,一個子產品僅完成一個獨立的功能,子產品内部不存在與該功能無關的操作或狀态。

舉一個生活中的例子。

有兩座城市Sidtown和Fredborough,連接配接兩座城市的公路一天到晚總是擁堵不堪。經過"有關部門"調查之後發現,這兩座城市中有兩家公司Better Mousetrap和 Zokko Soda,Better Mousetrap的工廠建造在Sidtown,而該工廠的員工都居住在Fredborough,是以每天早上大批員工從Fredborough出發前往Sidtown,并在傍晚傳回;類似的,Zokko Soda公司的運輸車在每天的工作時間都需要在制瓶工廠和灌裝工廠穿梭來往。

疊代器模式模式背景模式定義模式結構模式實作LuchMenu建立疊代器使用場景模式優缺點模式總結

很明顯,如果Better Mousetrap的工廠和員工居住地都在同一城市,而Zokko Soda的兩座工廠都建造在另一座城市,那麼城市之間的交通狀況将會明顯改善。

疊代器模式模式背景模式定義模式結構模式實作LuchMenu建立疊代器使用場景模式優缺點模式總結

對比兩圖,上面兩座城市間之是以出現交通的問題,是因為每座城市的"聚合性"都比較低:不相關的兩個公司出現在了同一座城市,使得城市内部交通的使用率比較低,而城市之間的交通出現了超負荷。

模式結構

疊代器模式模式背景模式定義模式結構模式實作LuchMenu建立疊代器使用場景模式優缺點模式總結

模式實作

公共接口

package com.nchu.iterator;

import java.util.Iterator;

public interface Menu {  
    public Iterator<MenuItem> createIterator();  
}  
           

疊代器的建立

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

BreakfastMenu建立疊代器

package com.nchu.iterator;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class BreakfastMenu implements Menu {

	private List<MenuItem> menuItems = new ArrayList<>();
	
	public void addMenuItem(MenuItem menuItem){
		menuItems.add(menuItem);
	}
	
	public void remove(MenuItem menuItem){
		menuItems.remove(menuItem);
	}
	
	public Iterator<MenuItem> createIterator() {  
        return menuItems.iterator();  
    }  
}
           

因為ArrayList自身就包含了疊代器的實作,是以這裡就可以直接傳回ArrayList的疊代器。

LuchMenu建立疊代器

package com.nchu.iterator;

import java.util.Iterator;

public class LuchMenu implements Menu {

	private MenuItem[] menuItems = new MenuItem[30];
	private int position = 0;
	
	public void addMenuItem(MenuItem menuItem){
		menuItems[position++] = menuItem;
	}
	
	public void remove(MenuItem menuItem){
		int i = 0;
		while(menuItems[i] != menuItem) ++i;
	}
	
	public Iterator<MenuItem> createIterator() {  
                return  new LunchIterator(menuItems, position);  
    }  
}
           

數組沒有疊代器的實作部分,是以與上面的建立方式會有所不同,此時正是疊代器模式大顯身手的時候。

自定義疊代器

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

package com.nchu.iterator;

import java.util.Iterator;



public class LunchIterator implements Iterator<MenuItem>{

	private MenuItem[] menuItems = null;  
    private int position = 0;
    private int index;
    
	public LunchIterator(MenuItem[] menuItems, int index) {
		this.menuItems = menuItems;
		this.index = index;
	}

	@Override
	public boolean hasNext() {
		if(menuItems == null)
			return false;
		return position < this.index;
	}

	@Override
	public MenuItem next() {
		MenuItem munuItem = menuItems[position++];
		return munuItem;
	}

	@Override
	public void remove() {
	}
}
           

疊代器組合

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

package com.nchu.iterator;

import java.util.Iterator;

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

菜品類

package com.nchu.iterator;

public class MenuItem {

	private String foodName;
	
	public MenuItem(String foodName) {
		this.foodName = foodName;
	}

	@Override
	public String toString() {
		return this.foodName;
	}
	
	
}
           

測試類

package com.nchu.iterator;

public class Client {

	public static void main(String[] args) {
		BreakfastMenu bm = new BreakfastMenu();
		bm.addMenuItem(new MenuItem("a"));
		bm.addMenuItem(new MenuItem("b"));
		bm.addMenuItem(new MenuItem("c"));
		
		LuchMenu lm = new LuchMenu();
		lm.addMenuItem(new MenuItem("d"));
		lm.addMenuItem(new MenuItem("e"));
		lm.addMenuItem(new MenuItem("f"));
		
//		Waitress wa = new Waitress(bm);
		Waitress wa = new Waitress(lm);
		
		wa.printMenu();
	}
}
           

使用場景

     1、通路一個聚合對象的内容而無須暴露它的内部表示。

      2、需要為聚合對象提供多種周遊方式。

      3、為周遊不同的聚合結構提供一個統一的接口。

模式優缺點

    優點

         1、它支援以不同的方式周遊一個聚合對象。

       2、疊代器簡化了聚合類。

       3、在同一個聚合上可以有多個周遊。

       4、在疊代器模式中,增加新的聚合類和疊代器類都很友善,無須修改原有代碼。

    缺點

        由于疊代器模式将存儲資料和周遊資料的職責分離,增加新的聚合類需要對應增加新的疊代器類,類的個數成對增加,這在一定程度上增加了系統的複雜性。

模式總結

        疊代器模式就是分離了集合對象的周遊行為,抽象出一個疊代器類來負責,這樣既可以做到不暴露集合的内部結構,又可讓外部代碼透明的通路集合内部資料。

繼續閱讀