天天看點

設計模式之疊代器模式案例示範内部疊代VS外部疊代補充知識——靜态疊代器和動态疊代器優缺點 最後

疊代器模式的定義是通過提供一種方法順序通路一個聚合對象中的各個元素,而又不必暴露該聚合對象中的内部表示。疊代器模式是針對聚合對象(數組、集合、連結清單)的“通路”而來。通過定義不同的周遊政策來周遊聚合對象。

應用場景

  1. 如果希望提供通路一個聚合對象的内容,但又不想暴露它的内部表示的時候可使用疊代器模式
  2. 如果希望有多種周遊方式可以通路聚合對象。
  3. 如果希望為周遊不同的聚合對象提供一個統一的接口,可以使用疊代器模式(多态疊代)。

UML圖

設計模式之疊代器模式案例示範内部疊代VS外部疊代補充知識——靜态疊代器和動态疊代器優缺點 最後

疊代器模式中涉及的角色:

  • 抽象疊代器角色(Iterator):此抽象角色定義出周遊元素的接口方法;
  • 具體疊代器角色(ConcreteIterator):實作具體的疊代方法,繼承或實作Iterator。
  • 聚集角色(Aggregate):定義聚集對象的抽象,并定義出具體的周遊接口傳回Iterator類型
  • 具體聚集角色(ConcreteAggregate):實作了建立疊代子(Iterator)對象的接口,傳回一個合适的具體疊代子執行個體。

案例示範

首先建立疊代器Iterator接口

/**
 * 定義疊代器角色
 * @author Iflytek_dsw
 *
 */
interface Iterator {
	/**
	 * 擷取第一個元素
	 * @return
	 */
	String first();
	/**
	 * 擷取最後一個元素
	 * @return
	 */
	String last();
	/**
	 * 判斷是否有下一個元素
	 * @return
	 */
	boolean hasNext();
	/**
	 * 下一個元素
	 * @return
	 */
	String next();
}
           

在Iterator接口中定義了聚集對象需要的周遊操作。

定義抽象聚集對象

/**
 * 聚集角色,定義聚集角色具備的接口
 * @author Iflytek_dsw
 *
 */
abstract class Aggregate {

	abstract Iterator iterator();
}
           

定義具體聚集對象

class ConcreteAggregate extends Aggregate{
	
	private List<String> names;

	public ConcreteAggregate(List<String> names) {
		super();
		this.names = names;
	}

	@Override
	Iterator iterator() {
		return new AggregateIterator(this);
	}
	
	public String first(){
		return names == null ? null : names.get(0);
	}
	
	public String last(){
		return names == null ? null : names.get(names.size() -1);
	}
	
	public String next(int index){
		return names == null ? null : names.get(index);
	}
	
	/**
	 * 聚集中的元素個數
	 * @return
	 */
	public int size(){
		return names.size();
	}
}
           

在上面的執行個體中,我們可以看到在具體聚集中,我們定義了與Iterator對象的方法,用來封裝具體的操作。以便在Iterator的具體執行個體中進行調用,同時我們也封裝了一個生成Iterator的方法。

具體疊代器

class AggregateIterator implements Iterator{
	private ConcreteAggregate concreteAggregate;
	private int index;
	public AggregateIterator(ConcreteAggregate concreteAggregate) {
		super();
		this.concreteAggregate = concreteAggregate;
		this.index = 0;
	}

	@Override
	public String first() {
		return concreteAggregate.first();
	}

	@Override
	public String last() {
		return concreteAggregate.last();
	}

	@Override
	public String next() {
		return concreteAggregate.next(index -1);
	}

	@Override
	public boolean hasNext() {
		if(index < concreteAggregate.size()){
			index++;
			return true;
		}
	    return false;
	}
}
           

在具體疊代器中定義包含一個聚集對象的執行個體,即對這個聚集對象進行相應操作的通路。

用戶端

public class Client {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		List<String> names = new ArrayList<>(Arrays.asList(new String[]{"James","Lucy","Jack"}));
		Aggregate aggregate = new ConcreteAggregate(names);
		Iterator iterator = aggregate.iterator();
		System.out.println("第一個元素是:" + iterator.first());
		System.out.println("最後一個元素是:" + iterator.last());
		
		while(iterator.hasNext()){
			System.out.println("周遊元素:" + iterator.next());
		}
	}
}
           

在上面的用戶端中,首先建立一個聚集類執行個體,然後調用iterator方法得到一個疊代器角色,得到疊代器角色後,我們就可以進行相關的周遊操作。

執行結果

第一個元素是:James
最後一個元素是:Jack
周遊元素:James
周遊元素:Lucy
周遊元素:Jack
           

通過上面的執行個體示範,我們可以得到以下幾點列:

  1. 疊代器的本質:控制通路聚合對象中的元素。疊代器能實作“無須暴露聚合對象的内部實作,就能夠通路到聚合對象的各個元素的功能”,做到“透明”的通路聚合對象中的元素。注意疊代器能夠即“透明”通路,又可以“控制通路”聚合對象。
  2. 疊代器的關鍵思想:把對聚合對象的周遊通路從聚合對象中分離出來,放入單獨的疊代器中,這樣聚合對象會變得簡單,而且疊代器和聚合對象可以獨立地變化和發展,提高系統的靈活性。
  3. 疊代器的動機:在軟體建構過程中,集合對象内部結構常常變化各異。但對于這些集合對象,我們希望在不暴露其内部結構的同時,可以讓外部客戶代碼透明地通路其中包含的元素;同時這種“透明周遊”也為“同一種算法在多種集合對象上進行操作”提供了可能。将周遊機制抽象為“疊代器對象”為“應對變化中的集合對象”提供了一種優雅的方法

在上面的例子中,既然聚集内部已經提供了相應的操作方法,那麼我們還要使用疊代器模式呢?确實,用戶端可以根據聚集提供的接口來進行周遊操作,但是,疊代器模式将疊代進行了抽象好,具有更好的擴充性,因為集合對象内部結構多變,使用疊代器模式可将用戶端和聚集的責任分割開,使得兩者可獨立演變,疊代器模式作為中間層,可以吸收變化因素,避免用戶端的修改。

内部疊代VS外部疊代

外部疊代器 指的是由用戶端來控制疊代下一個元素的步驟,用戶端會顯式調用疊代器的next()等疊代方法,在周遊過程中向前進行。

内部疊代器 指的是由疊代器自己來控制疊代下一個元素的步驟。是以,如果想要在疊代的過程中完成工作的話,用戶端就需要把操作傳遞給疊代器,疊代器在疊代的時候會在每個元素上執行這個操作,類似于JAVA的回調機制。

總體來說外部疊代器比内部疊代器要靈活一些,是以我們常見的實作多屬于主動疊代子。

如果一個聚集的接口沒有提供修改聚集元素的方法,這樣的接口就是所謂的窄接口。

聚集對象為疊代器提供了一個寬接口,為其它對象提供窄接口來通路。即聚集對象對疊代器是适當公開的,以便疊代器對聚集對象有足夠的了解,進而可以進行疊代操作。但是聚集對象應該避免向其它對象提供這些方法,其它對象應該通過疊代器完成這些操作,不能直接操作聚集對象。

在Java中,實作這種雙重限制接口的辦法就是通過内部類來實作,即将疊代器對象設定為聚集類的内部類,這樣疊代器對象可以對聚集類有很好的通路,同時又限制了對外的操作。這種同時保證聚集對象的封裝和疊代子功能的實作的方案叫做黑箱實作方案。而這種形式定義的疊代器,又被稱為内部疊代器。

如下面的例子所示:

public class NameRepository implements Container {
   public String names[] = {"Robert" , "John" ,"Julie" , "Lora"};

   @Override
   public Iterator getIterator() {
      return new NameIterator();
   }

   private class NameIterator implements Iterator {

      int index;

      @Override
      public boolean hasNext() {
         if(index < names.length){
            return true;
         }
         return false;
      }

      @Override
      public Object next() {
         if(this.hasNext()){
            return names[index++];
         }
         return null;
      }        
   }
}
           

補充知識——靜态疊代器和動态疊代器

靜态疊代器 靜态疊代子由聚集對象建立,并持有聚集對象的一份快照(snapshot),在産生後這個快照的内容就不再變化。用戶端可以繼續修改原聚集的内容,但是疊代子對象不會反映出聚集的新變化。

靜态疊代子的好處是它的安全性和簡易性,換言之,靜态疊代子易于實作,不容易出現錯誤。但是由于靜态疊代子将原聚集複制了一份,是以它的短處是對時間和記憶體資源的消耗。

動态疊代器 動态疊代子則與靜态疊代子完全相反,在疊代子被産生之後,疊代子保持着對聚集元素的引用,是以,任何對原聚集内容的修改都會在疊代子對象上反映出來。

完整的動态疊代子不容易實作,但是簡化的動态疊代子并不難實作。大多數JAVA設計師遇到的疊代子都是這種簡化的動态疊代子。為了說明什麼是簡化的動态疊代子,首先需要介紹一個新的概念:Fail Fast。

Fail Fast 如果一個算法開始之後,它的運算環境發生變化,使得算法無法進行必需的調整時,這個算法就應當立即發出故障信号。這就是Fail Fast的含義。

如果聚集對象的元素在一個動态疊代子的疊代過程中發生變化時,疊代過程會受到影響而變得不能自恰。這時候,疊代子就應當立即抛出一個異常。這種疊代子就是實作了Fail Fast功能的疊代子。

Fail Fast在JAVA聚集中的使用 JAVA語言以接口java.util.Iterator的方式支援疊代子模式,Collection接口要求提供iterator()方法,此方法在調用時返還一個Iterator類型的對象。而作為Collection接口的子類型,AbstractList類的内部成員類Itr便是實作Iterator接口的類。

優缺點

優點

  1. 更好的封裝性,聚集對象不需要暴露内部實作即可實作通路;
  2. 每一個聚集對象都可以有一個或多個疊代子對象,每一個疊代子的疊代狀态可以是彼此獨立的。是以,一個聚集對象可以同時有幾個疊代在進行之中。
  3. 聚集内容和疊代器的分離,提高了擴充性,即可以使用不同的疊代器來周遊聚集内容。

缺點

  1. 疊代器種類過多,會導緻類的個數增加,提高了系統的複雜性;
  2. 在動态疊代器中易發生異常。

 最後

一直想整理出一份完美的面試寶典,但是時間上一直騰不開,這套一千多道面試題寶典,結合今年金三銀四各種大廠面試題,以及 GitHub 上 star 數超 30K+ 的文檔整理出來的,我上傳以後,毫無意外的短短半個小時點贊量就達到了 13k,說實話還是有點不可思議的。

需要完整版的小夥伴,可以一鍵三連後,點選這裡!

一千道網際網路 Java 工程師面試題

内容涵蓋:Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、Redis、MySQL、Spring、SpringBoot、SpringCloud、RabbitMQ、Kafka、Linux等技術棧(485頁)

設計模式之疊代器模式案例示範内部疊代VS外部疊代補充知識——靜态疊代器和動态疊代器優缺點 最後

《Java核心知識點合集(283頁)》

内容涵蓋:Java基礎、JVM、高并發、多線程、分布式、設計模式、Spring全家桶、Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、MongoDB、Redis、MySQL、RabbitMQ、Kafka、Linux、Netty、Tomcat、資料庫、雲計算等

設計模式之疊代器模式案例示範内部疊代VS外部疊代補充知識——靜态疊代器和動态疊代器優缺點 最後

《Java中進階核心知識點合集(524頁)》

設計模式之疊代器模式案例示範内部疊代VS外部疊代補充知識——靜态疊代器和動态疊代器優缺點 最後

《Java進階架構知識點整理》

設計模式之疊代器模式案例示範内部疊代VS外部疊代補充知識——靜态疊代器和動态疊代器優缺點 最後
設計模式之疊代器模式案例示範内部疊代VS外部疊代補充知識——靜态疊代器和動态疊代器優缺點 最後
設計模式之疊代器模式案例示範内部疊代VS外部疊代補充知識——靜态疊代器和動态疊代器優缺點 最後

 由于篇幅限制,詳解資料太全面,細節内容太多,是以隻把部分知識點截圖出來粗略的介紹,每個小節點裡面都有更細化的内容!

需要完整版的小夥伴,可以一鍵三連後,點選這裡!