2008年5月9日 星期五

For Each 面面觀與實作

今天要來討論的是...很快樂的for each!!目前眾多OO程式語言都有支援這類的語法,在不需要index的時候用起來還蠻方便的。我們知道說,像是在眾多的implements collection的類別中,都可以使用此語法,不過在一些我們所設計之特殊的資料結構(ADT, class)上,往往可能需要此類語法的支援,那麼怎樣才能夠針對我們所撰寫的資料結構,讓for each也能夠跑呢?

像是Ruby在前幾篇文章就有提到說,要如何實作其for each語法。在Ruby中是使用了Block的觀念去把上層的程式碼交給下層來處理,也就是說只要能提供類似 .each方法,逐一將直送進yield中即可達成我們要的目標。所以今天我們就來討論一下在JAVA要怎樣來實作。

首先我們先觀察一下目前有哪些類別可以被for each實作...google很快就跟我們說,像是List、Set、HashSet等等,繼承這些介面的類別都可以。透過查看Java doc我們可以很簡單的查覺,這些介面都是繼承於一個名叫做Iterable的介面,點進去看一下,嗯...很好,很清楚著寫著說,只要實作此介面者,都可以被for each所使用,只要在類別中把方法Iterator iterator()實作即可。於是,我們可以在繼續往下觀察Iterator...不過這邊就不再寫下去(學會看Java doc畢竟是基本工不是嗎?再說下去就會汙辱到看官的智商了)。

整理一下目前的情報,如果要能實作for each就必須實作自Iterable;而要實作Iterable,就必須要提供一個iterator。而一個iterator就需要實作三個方法boolean hasNext()、E next()、void remove()。其中remove則不一定要寫程式碼在裡面,看需求而定。而這邊就提供一個簡單而沒啥意義的簡單範例


因為這個blog本身不適合張貼程式碼(空白會被吃掉),所以就將就一下,對照著看唄。在這個程式碼中,Node是最基礎的元件(類別),一方面是為了將抽象化的層次提高,另一方面則是Iterable本身需要參考的類別(ADT),而不能是基礎資料型態。而Nodes當然就是我們所需要的可以被foreach之類別,裡面提供了加入和刪除。最後是實作Iterator的Itr,基本上將Iterator放在Iterable的子類別是個不錯的選擇,可以很容易自在的取得上層類別的方法與物件。不過這次我是將整個Iterator寫的比較鬆,以利往後也許還有機會可以直接抓過來用,僅僅在remove用到了上層類別的delete,如果不要remove,獨立出來也是可以。

所以其實整個實作的重點就在於要丟出一個Iterator,其可以提供判斷還有沒有下一個元素(hasNext),亦要提供一個方法可以依序丟出集合中的元素(next)。Iterator 怎麼實作就是隨意了,不過基本上還是跟實作Iterable的類別脫離不了關係。這麼辛苦做出來的東西...實用性有多大是不知道(範例是沒啥用的XD),不過如果善加利用也許能夠增加整個程式的效率。

而如果覺得寫那麼多,卻沒啥fu,那還不如直接去繼承ArrayList等類別,善加利用類別中已經提供的方法,還是可以達到製作容器的目的,而且人家早就把程式碼寫好,可以專心處理類別中的其他部分,照樣還是可以用foreach。
(下次來挑戰看看VB好了XD)

沒有留言: