過濾器集合
???????????????????????????????????? --一個(gè)實(shí)現(xiàn)過濾器集合的簡(jiǎn)易的通用機(jī)制
????????????????????????????????????????????????? By David Rappoport, JavaWorld.com, 10/18/04
???
經(jīng)常地,你必須遍歷一個(gè)對(duì)象集合并基于一些條件(criteria)來過濾它們。JDK提供了有用的機(jī)制來排序集合,即Comparator接口。然而,JDK缺少過濾集合的機(jī)制。??? 這篇文章描述了一個(gè)僅由一個(gè)類和一個(gè)接口組成的簡(jiǎn)單機(jī)制,它允許你快速和靈活地過濾集合。當(dāng)搜索一個(gè)集合時(shí),該機(jī)制提供了與SQL中的select語句相同的功能。它的隱含的概念是,在遍歷集合和過濾集合中的對(duì)象時(shí),達(dá)到職責(zé)的分離。
??? 這里提出的方法有下面的優(yōu)點(diǎn):
??? 1、一個(gè)核心的過濾器組件的復(fù)用產(chǎn)生更清晰的代碼。
??? 2、通用過濾組件的復(fù)用產(chǎn)生更免于錯(cuò)誤的代碼。
??? 3、從過濾邏輯中分離出迭代邏輯使你任意地增加和刪除過濾器而不影響到其他代碼。
??? 4、對(duì)于大集合和多個(gè)criteria能夠獲得性能提高。
問題
??? 想象一個(gè)搜索接口(mask),用戶通過選擇眾多不同的條件(criteria)來搜索汽車。為了簡(jiǎn)單地完成這個(gè)任務(wù),開發(fā)者必須多次遍歷(iterate)集合。在每一次遍歷中,他必須對(duì)集合中的每一個(gè)對(duì)象執(zhí)行一定的邏輯來確定該對(duì)象是否滿足條件(criteria)。通常,這個(gè)過程的結(jié)果是很難閱讀和維護(hù)的凌亂的代碼。
解決辦法
??? 我們定義了一個(gè)類CollectionFilter和一個(gè)接口FilterCriteria。FilterCriteria僅僅定義了一個(gè)方法:public boolean passes(Object o)。這個(gè)方法中,集合中的一個(gè)對(duì)象必須通過一定的測(cè)試。如果它通過測(cè)試,該方法返回true,否則返回false。CollectionFilter接收一些FilterCriteria作為輸入。然后你能調(diào)用public void filter(Collection)方法,該方法應(yīng)用了集合中所有的FilterCriteria,并刪除集合中沒有通過所有FilterCriteria的任何對(duì)象。
CollectionFilter類也定義了public Collection filterCopy(Collection)方法,它完成和filter(Collection)方法相同的任務(wù),但對(duì)原始的過濾器做了復(fù)制。代碼如下(譯者添加):
package?com.drap.filter;
/**
?*?<p>Title:?FilterCriteria</p>
?*?<p>Description:?A?FilterCriteria?is?added?to?the?CollectionFilter?to?filter
?*?all?the?objects?in?the?collection.?</p>
?*?@author?David?Rappoport
?*?@version?1.0
?*/
public?interface?FilterCriteria?{
????/**
?????*?Implement?this?method?to?return?true,?if?a?given?object?in?the?collection
?????*?should?pass?this?filter.
?????*?Example:?Class?Car?has?an?attribute?color?(String).?You?only?want?Cars
?????*?whose?color?equals?"red".
?????*?1)?Write?the?FilterCriteria?implementation:
?????*?class?RedColorFilterCriteria?implements?FilterCriteria{
?????*?????public?boolean?passes(Object?o){
?????*?????????return?((Car)o).getColor().equals("red");
?????*?????}
?????*?}
?????*?2)?Then?add?this?FilterCriteria?to?a?CollectionFilter:
?????*?CollectionFilter?filter?=?new?CollectionFilter();
?????*?filter.addFilterCriteria(new?ColorFilterCriteria());
?????*?3)?Now?filter:
?????*?filter.filter(carCollection);
?????*?@param?o
?????*?@return
?????*/
????public?boolean?passes(Object?o);
}
package?com.drap.filter;
import?java.lang.reflect.*;
import?java.util.*;
/**
?*?<p>Title:?CollectionFilter</p>
?*?<p>Description:?</p>
?*?@author?David?Rappoport
?*?@version?1.0
?*/
public?class?CollectionFilter?implements?java.io.Serializable?{
??? private?ArrayList?allFilterCriteria?=?new?ArrayList();
??? /**
?????*?Adds?a?FilterCriteria?to?be?used?by?the?filter
?????*?@param?filterCriteria
?????*/
????public?void?addFilterCriteria(FilterCriteria?filterCriteria){
????????allFilterCriteria.add(filterCriteria);
????}
????/**
?????*?Starts?the?filtering?process.?For?each?object?in?the?collection,
?????*?all?FilterCriteria?are?called.?Only?if?the?object?passess
?????*?all?FilterCriteria?it?remains?in?the?collection.?Otherwise,?it?is?removed.
?????*?@param?collection
?????*/
????public?void?filter(Collection?collection){
??????? if(collection?!=?null){
????????????Iterator?iter?=?collection.iterator();
????????????while(iter.hasNext()){
????????????????Object?o?=?iter.next();
????????????????if(!passesAllCriteria(o)){
????????????????????iter.remove();
????????????????}
????????????}
????????}
????}
????/**
?????*?This?method?does?the?same?as?the?filter?method.?However,?a?copy?of
?????*?the?original?collection?is?created?and?filtered.?The?original?collection
?????*?remains?unchanged?and?the?copy?is?returned.?Only?use?this?method
?????*?for?collection?classes?that?define?a?default?constructor
?????*?@param?inputCollection
?????*?@return?a?filtered?copy?of?the?input?collection
?????*/
????public?Collection?filterCopy(Collection?inputCollection){
????????Collection?outputCollection?=?null;
????????if(inputCollection?!=?null){
??????????? outputCollection?=?(Collection)createObjectSameClass(inputCollection);
????????????outputCollection.addAll(inputCollection);
????????????Iterator?iter?=?outputCollection.iterator();
????????????while(iter.hasNext()){
????????????????Object?o?=?iter.next();
????????????????if(!passesAllCriteria(o)){
????????????????????iter.remove();
????????????????}
??????????? }
????????}
????????return?outputCollection;
????}
????/**
?????*?Makes?sure?the?specified?object?passes?all?FilterCriteria's?passes?method.
?????*?@param?o
?????*?@return
?????*/
????private?boolean?passesAllCriteria(Object?o){
????????for(int?i?=?0;?i?<?allFilterCriteria.size();?i?++){
????????????FilterCriteria?filterCriteria?=?(FilterCriteria)allFilterCriteria.get(i);
????????????if(!filterCriteria.passes(o)){
????????????????return?false;
??????????? }
????????}
????????return?true;
????}
????/**
?????*?Call?the?no?arguments?constructor?of?the?object?passed
?????*?@param?object
?????*?@return
?????*/
????public?Object?createObjectSameClass(Object?object){
??????? Class[]?NO_ARGS?=?new?Class[0];
????????Object?sameClassObject?=?null;
????????try{
????????????if(object?!=?null){
????????????????Constructor?constructor?=?object.getClass().getConstructor(NO_ARGS);
????????????????sameClassObject?=?constructor.newInstance(NO_ARGS);
????????????}
????????}catch(IllegalAccessException?e){
????????????//@todo?do?something
????????}catch(NoSuchMethodException?e){
????????????//@todo?do?something
????????}catch(InstantiationException?e){
????????????//@todo?do?something
????????}catch(Exception?e){
????????????//@todo?do?something
????????}
????????return?sameClassObject;
????}
}
??? 就是這樣了!
??? 就像你可能已經(jīng)注意到了,這個(gè)解決方法使用了職責(zé)鏈設(shè)計(jì)模式的部分思想并應(yīng)用它們到集合中。
??? 下面的類圖說明了類和接口及它們之間的關(guān)系。
簡(jiǎn)單的例子
??? 讓我們看一個(gè)例子:類car有三個(gè)屬性:String color, double maxSpeed, boolean fourWheelDrive。
你的應(yīng)用程序允許基于這些條件來搜索cars:用戶能輸入她喜歡的顏色,她也能提供她想要car擁有的最大速度,及car是否支持four-wheel驅(qū)動(dòng)。
??? 我們現(xiàn)在創(chuàng)建三個(gè)過濾器類來滿足用戶選擇的條件。
??? 1、FilterCriteria的實(shí)現(xiàn)如下:
class?ColorFilterCriteria?implements?FilterCriteria{
????private?String?color;
????public?boolean?passes(Object?o){
????????return?((Car)o).getColor().equals(color);
????}
}
class?MaxSpeedFilterCriteria?implements?FilterCriteria{
????private?int?maxSpeed;
????public?boolean?passes(Object?o){
????????return?((Car)o).getMaxSpeed()?>=?maxSpeed;
????}
}
class?FourWheelDriveFilterCriteria?implements?FilterCriteria{
????private?boolean?fourWheelDriveRequired;
????private?boolean?fourWheelDriveAllowed;
????public?boolean?passes(Object?o){
????????return?fourWheelDriveRequired?((Car)o).isFourWheelDrive():fourWheelDriveAllowed?true:!
????((Car)o).isFourWheelDrive();
????}
}
??? 2、添加這些FilterCriteria到CollectionFilter中。
CollectionFilter?collectionFilter?=?new?CollectionFilter();
filter.addFilterCriteria(new?ColorFilterCriteria(color));
filter.addFilterCriteria(new?MaxSpeedFilterCriteria(maxSpeed));
filter.addFilterCriteria(new?FourWheelDriveFilterCriteria(fourWheelDriveRequired,?fourWheelDriveAllowed));
??? 3、調(diào)用過濾方法:
collectionFilter.filter(carCollection);
技術(shù)的使用(Technicalities)
??? 正如你可能意識(shí)到的,和Comparator接口中的compare(Object o1, Object o2)方法相似,F(xiàn)ilterCriteria接口中的passes(Object o)方法接收任何類型的對(duì)象作為輸入?yún)?shù)。這意味著你必須將對(duì)象轉(zhuǎn)換成你想要工作的類型并確保你的集合中僅僅包含那種類型的對(duì)象。如果這個(gè)不是確定的,你能使用instanceof測(cè)試指定的對(duì)象是否為那種類型。(譯者注:根據(jù)需要,可以使用范型解決類型轉(zhuǎn)換問題,由于這篇文章實(shí)在是太早了,所以作者才有了這段內(nèi)容。)
??? 有時(shí)候,你可能不喜歡為每一個(gè)FilterCriteria定義一個(gè)單獨(dú)的類,這種情況下可以使用匿名的內(nèi)部類。
為了使解決方法簡(jiǎn)單些,我對(duì)這個(gè)過濾器并沒有使用OR功能。換句話說,每次你增加一個(gè)FilterCriteria到你的CollectionFilter,可以當(dāng)作是SQL中的AND操作。然而,你也能容易的在一個(gè)FilterCriteria增加像OR的功能。例如:
class?EitherOrColorFilterCriteria?implements?FilterCriteria{
????private?String?color1;
????private?String?color2;
????public?boolean?passes(Object?o){
????????return?((Car)o).getColor().equals(color1)?||?((Car)o).getColor().equals(color2);
????}
}
結(jié)論
??? 如你所看到的,基于多個(gè)條件來過濾集合是簡(jiǎn)單的。每一個(gè)FilterCriteria對(duì)象僅對(duì)它表示的單個(gè)的過濾邏輯負(fù)責(zé)。CollectionFilter然后聯(lián)合所有的過濾器來產(chǎn)生想要的結(jié)果。對(duì)于其它種類的集合處理的相似的解決方法也是可以想到的(除了刪除操作)。這個(gè)解決方法使用了職責(zé)鏈和迭代器模式:CollectionFilter在集合之上迭代,對(duì)于集合中的每一個(gè)對(duì)象,F(xiàn)ilterCriteria對(duì)象被當(dāng)作職責(zé)鏈,而每一個(gè)過濾器能決定其它的過濾器是否是需要的。
作者Bio David Rappoport 已經(jīng)在IBM Global Services 和 Credit Suisse Application Development 工作了五年, 在那兒他開發(fā)J2EE領(lǐng)域的軟件。他是一個(gè)SUN認(rèn)證的Java 2 程序員,SUN認(rèn)證的Java 2開發(fā)者,SUN認(rèn)證的J2EE 架構(gòu)師,和SUN認(rèn)證的業(yè)務(wù)組件開發(fā)者。他和他的妻子幾兩個(gè)孩子生活在瑞士。
注:該文為本人第一篇和技術(shù)相關(guān)的翻譯文章(論文就不算了)。由于本人水平有限,翻譯中難免有不對(duì)的地方,歡迎各位朋友指正。該文出處為http://www.javaworld.com/javaworld/jw-10-2004/jw-1018-filter.html,是一篇很早的文章(2004年),內(nèi)容上也算是比較簡(jiǎn)單的。