java 迭代器模式實例詳解
java 迭代器模式實例詳解
今天來818設(shè)計模式中的迭代器模式,也是java中Stack,List,Set等接口以及數(shù)組這個數(shù)據(jù)結(jié)構(gòu)都會使用的一種模式。
首先,為什么使用迭代器模式,目的就是通過一個通用的迭代方法,隱藏stack,list,set以及數(shù)組中不同的遍歷細節(jié)。也就是說,我不想讓那些調(diào)用我的遍歷容器的方法的人知道我到底是怎么一個一個的獲取這些元素的(stack的pop,list的get,數(shù)組的array[i]),我只想讓他知道他能 通過一個迭代器Iterator或者通過一個for each語句就能拿到我容器里面所有的元素。這樣就能夠最大化的隱藏實現(xiàn)細節(jié),封裝變化了。
先通過一個例子來一步步了解這其中的重要性吧。比方說,我要開發(fā)一個平臺,這個平臺會獲取到京東的訂單和淘寶的訂單,然后把訂單中的所有購買條目全部打印出來。
既然要打印訂單中的所有條目,那么就得先知道這些條目,也就是訂單項有哪些屬性。
package iterator; /** * * @ClassName: Item * @Description: 訂單項 * @author minjun * */ public class Item { /**商品名稱*/ private String name; /**價格*/ private double price; /**描述*/ private String desc; /**數(shù)量*/ private int count; public Item(String name, double price, String desc, int count) { this.name = name; this.price = price; this.desc = desc; this.count = count; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public int getCount() { return count; } public void setCount(int count) { this.count = count; } @Override public String toString() { return "Item [name=" + name + ", price=" + price + ", desc=" + desc + ", count=" + count + "]"; } }
知道了這個條目,然后我想看看京東和淘寶是如何存儲這些條目的。于是我問了問劉強東和馬云,得知京東是用集合List存儲,因為方便,而淘寶是用數(shù)組存儲。他們都不愿意修改存儲的容器,因為改動太大。
這時, 如果用傳統(tǒng)想法,ok,我拿到京東的List,然后通過for循環(huán)和list.get(i)獲取里面的每個條目并打印。然后拿到淘寶的array,通過for循環(huán)和array[i]獲取里面的條目并打印。是不是可以實現(xiàn)呢?確實可以,但是我發(fā)現(xiàn)這樣的話,每個容器我都要實現(xiàn)一遍不同的打印方法。目前是兩個倒還好,如果又來個誰誰誰,用鏈表來實現(xiàn)容器,那我是不是又要新加一個迭代鏈表的方法呢?我當然不會愿意,因為這樣太麻煩了。于是乎,我有個想法,思路是這樣的:
我希望讓京東的訂單和淘寶的訂單都是可以方便的遍歷里面的元素,遍歷的方法能夠通過一個公共的方法來處理,而不是像之前那個分別做處理。根據(jù)這個思路,用TDD(測試驅(qū)動開發(fā))來做步驟實現(xiàn)。先寫好測試代碼,首先我要有個訂單接口,里面有兩個子類訂單(淘寶訂單和京東訂單):
package iterator; import org.junit.Test; public class TestCase { @Test public void test() { Order o = new TBOrder();//淘寶的訂單 // new JDOrder();//京東的訂單 printOrder(o);//打印訂單 } /**打印訂單 */ private void printOrder(Order o) { for (Item item : o) { System.out.println(item); } } }
如果能像上述這樣打印,那會多么方便啊。如果換成淘寶訂單,就用淘寶的訂單迭代實現(xiàn),換成京東的訂單,就用京東的訂單實現(xiàn),我在測試代碼根本不需要關(guān)注實現(xiàn)細節(jié)?,F(xiàn)在我會想,如果能通過什么方法直接打印這個訂單Order中的所有條目,那才能完整的實現(xiàn)我上述的代碼。也就是說我需要我的訂單是可以遍歷的,那應(yīng)該怎么做呢?其實java中提供了這樣的接口,就是Iterable,如果我的訂單都實現(xiàn)了這個接口,那么我的訂單自然而然就可以通過一個for each循環(huán)來遍歷里面的內(nèi)容。
/* * %W% %E% * * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package java.lang; import java.util.Iterator; /** Implementing this interface allows an object to be the target of * the "foreach" statement. * @since 1.5 */ public interface Iterable<T> { /** * Returns an iterator over a set of elements of type T. * * @return an Iterator. */ Iterator<T> iterator(); }
上面是java的Iterable接口,下面是我自己的訂單接口,繼承了Iterable接口
package iterator; public interface Order extends Iterable<Item>{ }
注意上面的Order訂單接口繼承了Iterable接口之后,同樣也繼承過來了一個抽象方法iterator。這個抽象方法才是Iterable的根本實現(xiàn)方案。我們會在子類訂單中分別實現(xiàn)這個接口,然后提供京東和淘寶不同的迭代方案。
京東
package iterator; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * * @ClassName: JDOrder * @Description: 京東訂單 * @author minjun * */ public class JDOrder implements Order { /** 京東用集合裝訂單項 */ private List<Item> list = new ArrayList<Item>(); public JDOrder() { add("iphone6", 5000.00, "一部手機", 2); add("mbp", 16000.00, "一臺電腦", 1); add("西門子洗衣機", 3000.00, "一臺洗衣機", 3); } /** 添加訂單條目 */ public void add(String name, double price, String desc, int count) { list.add(new Item(name, price, desc, count)); } @Override public Iterator<Item> iterator() { return new MyIterator(); } private class MyIterator implements Iterator<Item> { private Iterator<Item> it = list.iterator(); @Override public boolean hasNext() { return it.hasNext(); } @Override public Item next() { return it.next(); } @Override public void remove() { throw new UnsupportedOperationException("目前不支持刪除操作"); } } }
淘寶
package iterator; import java.util.Iterator; import java.util.NoSuchElementException; /** * * @ClassName: TBOrder * @Description: 淘寶訂單 * @author minjun * */ public class TBOrder implements Order{ private int size=3; private Item[] orders=new Item[size]; private int index=0; public TBOrder(){ add("天貓1", 1111, "天貓活動1", 1); add("天貓2", 1111, "天貓活動1", 1); add("天貓3", 1111, "天貓活動1", 1); add("天貓4", 1111, "天貓活動1", 1); add("天貓5", 1111, "天貓活動1", 1); add("天貓6", 1111, "天貓活動1", 1); add("天貓7", 1111, "天貓活動1", 1); add("天貓8", 1111, "天貓活動1", 1); } /**添加訂單條目*/ public void add(String name, double price, String desc, int count) { //如果超過數(shù)組大小,就擴容 if(index>=size-1){ resize(); } orders[index++]=new Item(name, price, desc, count); } /**擴容*/ private void resize() { size=size<<1;//移位運算符--相當于size=size*2 Item[] newItems=new Item[size]; //將原始數(shù)組內(nèi)容拷貝到新數(shù)組中去 for(int i=0;i<orders.length;i++){ newItems[i]=orders[i]; } orders=newItems; } @Override public Iterator<Item> iterator() { return new MyIterator(); } private class MyIterator implements Iterator<Item>{ private int curr=0; @Override public boolean hasNext() { return orders[curr]!=null; } @Override public Item next() { if(hasNext()){ return orders[curr++]; }else{ throw new NoSuchElementException("沒有這個元素"); } } @Override public void remove() { throw new UnsupportedOperationException("目前不支持刪除操作"); } } }
這樣,我就做到了提供一個標準的可以迭代的Order訂單接口,然后以兩種不同的迭代實現(xiàn)方案(京東、淘寶),為我們的測試類提供了一個可以屏蔽掉內(nèi)部不同容器的具體實現(xiàn)區(qū)別。同時,這也是迭代器模式的運用。
總結(jié):需求--不同容器不同迭代方案,改進--利用相同迭代方案來處理,將不同實現(xiàn)細節(jié)分別隱藏到容器自己的實現(xiàn)中。采用的方案就是實現(xiàn)Iterable接口,以及里面的Iterator方法,然后實現(xiàn)自己的迭代方式。
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
相關(guān)文章
springboot+Quartz實現(xiàn)任務(wù)調(diào)度的示例代碼
本篇文章主要介紹了springboot + Quartz 實現(xiàn)任務(wù)調(diào)度的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-02-02Java對象轉(zhuǎn)Json,關(guān)于@JSONField對象字段重命名和順序問題
這篇文章主要介紹了Java對象轉(zhuǎn)Json,關(guān)于@JSONField對象字段重命名和順序問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08SpringBoot使用validation-api實現(xiàn)對枚舉類參數(shù)校驗的方法
這篇文章主要介紹了SpringBoot使用validation-api實現(xiàn)對枚舉類參數(shù)校驗,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-11-11mybatis(mybatis-plus)映射文件(XML文件)中特殊字符轉(zhuǎn)義的實現(xiàn)
XML 文件在解析時會將五種特殊字符進行轉(zhuǎn)義,本文主要介紹了mybatis(mybatis-plus)映射文件(XML文件)中特殊字符轉(zhuǎn)義的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下2023-12-12Java中List轉(zhuǎn)Map的幾種常見方式與對比
JavaList轉(zhuǎn)Map是一個非常常用的技術(shù),對于Java開發(fā)人員來講,掌握該技術(shù)可以幫助我們更加高效地操作List集合中的對象,這篇文章主要給大家介紹了關(guān)于Java中List轉(zhuǎn)Map的幾種常見方式與對比的相關(guān)資料,需要的朋友可以參考下2024-02-02