http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=125&threadID=27195
Design Pattern Practice 1.序 本文從一個簡單的多列排序的例子入手,由淺入深地講解Design Pattern(設計模式)的目的、分析和實踐。 文中的例子用到Compositor Pattern和Decorator Pattern。 同時,文中的例子也提供了一類問題(條件組合問題)的解決方案。
2.問題的引入 Design Pattern(設計模式)的目標是,把共通問題中的不變部分和變化部分分離出來。不變的部分,就構成了Design Pattern(設計模式)。這一點和Framework(框架)有些象。 下面舉個排序的例子,說明如何抽取問題中的不變部分。 假設一個Java類Record有field1,field2,field3等字段。 java代碼:?
 public?class?Record {?
????????public?int?field1;?
????????public?long?field2;?
????????public?double?filed3;?
};?
我們還有一個Record對象的數組Record[] records。我們需要對這個數組按照不同的條件排序。 首先,按照field1的大小從小到大進行升序排序。 排序函數如下: java代碼:?
 void?sort(Record[]?records) {?
 ????????for(int?i?=….) {?
 ????????????????for(int?j=….) {?
????????????????????????if(records.field1?>?records[j].field1)?
????????????????????????????????//?swap?records?and?records[j]?
????????????????}?
????????}?
}?
其次,按照field2的大小從小到大進行升序排序。 java代碼:?
 void?sort(Record[]?records) {?
 ????????for(int?i?=….) {?
 ????????????????for(int?j=….) {?
????????????????????????if(records.field2?>?records[j].field2)?
????????????????????????????????//?swap?records?and?records[j]?
????????????????}?
????????}?
}?
再次,按照field3的大小從小到大進行升序排序。 這種要求太多了,我們寫了太多的重復代碼。我們可以看到,問題的變化部分,只有判斷條件部分(黑體的if條件判斷語句)。 我們可以引入一個Comparator接口,把這個變化的部分抽取出來。 java代碼:?
 public?interface?Comparator() {?
????????public?boolean?greaterThan(Record?a,?Record?b);?
};?
sort函數就可以這樣寫(把判斷條件作為參數):?
 void?sort(Record[]?records,?Comparator?compare) {?
 ????????for(int?i?=….) {?
 ????????????????for(int?j=….) {?
????????????????????????if(compare.greaterThen(records,?records[j]))?
????????????????????????????????//?swap?records?and?records[j]?
????????????????}?
????????}?
}?
這樣,對應第一個要求——對records數組按照field1的大小排序。 我們可以做一個實現Comparator接口的CompareByField1類。 java代碼:?
 public?class?CompareByField1?implements?Comparator {?
 public?boolean?greaterThan(Record?a,?Record?b) {?
 ????????if(a.filed1?>?b.filed1) {?
????????????????return?ture;?
????????}?
????????return?false;?
}?
}?
sort函數的調用為:sort(records, new CompareByField1());
這樣,對應第一個要求——對records數組按照field2的大小排序。 我們可以做一個實現Comparator接口的CompareByField2類。
java代碼:?
 public?class?CompareByField2?implements?Comparator {?
 public?boolean?greaterThan(Record?a,?Record?b) {?
 ????????if(a.filed2?>?b.filed2) {?
????????????????return?ture;?
????????}?
????????return?false;?
}?
}?
sort函數的調用為:sort(records, new CompareByField2()); 按照C++ STL的叫法,這里的sort稱為算法(Algorithm),records稱為容器(集合),Comparator稱為函數對象(Function Object)。
JDK的java.util.Collections類的sort方法和java.util.Comparator接口就是按照這樣的思路設計的。下面我們來看看如何應用sort和Comparator解決多列排序問題。
3.多列排序問題 3.1排序條件的數量 我們知道,SQL語句能夠實現強大的排序功能,能夠按照不同字段的排列進行排序,也能夠按照升序,降序排序。比如下面的語句。 order by field1 asc, field2 asc, field3 desc。
這個排序條件按照field1的升序,field2的升序,field3的降序排序。 注意,排在前面的字段具有較高的優先級。 比如,兩條紀錄A和B,滿足如下條件:(1)A.field1 > B.field1,(2)A.field2 < B.field2。 這時如果按照order by field1, field2語句排序,那么 A > B。 如果上述條件中的(1)A.field1 > B.field1變化為A.field1 == B.field1。這時,條件(2)就會起作用。這時,A < B。
我們來看看在Java中如何實現這種靈活而強大的排序。 我們還是以上一節的Record類為例。Record類有3個字段,我們來看一看,有多少種可能的排序條件。 (1)按field1排序。(2)按field2排序。(3)按field3排序。(4)按field1,field2排序。(5)按field1升序,按field2降序排序…...
各種排序條件的排列組合,大概共有30種。而且,隨著字段個數的增長,排序條件的個數呈冪級數的增長。 按照上一節的sort和Comparator方法,如果我們需要達到按照任意條件進行排序的目的,那么我們需要為每一個排序條件提供一個Comparator,我們需要30個Comparator類。 當然,我們不會這么做,我們能夠進一步提取這個問題中的相同重復部分,優化我們的解決方案。
3.2 問題分析 我們來分析這個問題中變化的部分和不變的部分。 上面所有的排序條件中,不變的部分有3部分:(1)A.field1和B.field1的比較,(2)A.field2和B.field2的比較,(3)A.field3和B.field3的比較;變化的部分有兩部分,(1)這三種比較條件的任意組合排列,(2)升序和降序。 根據這段分析,我們引入兩個類,ReverseComparator類和CompositeComparator類。 CompositeComparator類用來解決字段的組合排列問題。 ReverseComparator類用來解決字段的升序、降序問題。
3.3 ReverseComparator類的代碼
java代碼:?
import?java.util.Comparator;?

 public?class?ReverseComparator?implements?Comparator {?
 ??/**?*//**?the?original?comparator*/?
??private?Comparator?originalComparator?=?null;?

 ??/**?*//**?constructor?takes?a?comparator?as?parameter?*/?
 ??public?ReverseComparator(Comparator?comparator) {?
????originalComparator?=?comparator;?
??}?

 ??/**?*//**?reverse?the?result?of?the?original?comparator?*/?
 ??public?int?compare(Object?o1,?Object?o2) {?
????return?-?originalComparator.compare(o1,?o2);?
??}?
}?

3.4 CompositeComparator類的代碼
java代碼:?
import?java.util.Comparator;?
import?java.util.Iterator;?
import?java.util.List;?
import?java.util.LinkedList;?

 public?class?CompositeComparator?implements?Comparator {?
 ??/**?*//**?in?the?condition?list,?comparators'?priority?decrease?from?head?to?tail?*/?
??private?List?comparators?=?new?LinkedList();?

 ??/**?*//**?get?the?comparators,?you?can?manipulate?it?as?need.*/?
 ??public?List?getComparators() {?
????return?comparators;?
??}?

 ??/**?*//**?add?a?batch?of?comparators?to?the?condition?list?*/?
 ??public?void?addComparators(Comparator[]?comparatorArray) {?
 ????if(comparatorArray?==?null) {?
??????return;?
????}?

 ????for(int?i?=?0;?i?<?comparatorArray.length;?i++) {?
??????comparators.add(comparatorArray);?
????}?
??}?

 ??/**?*//**?compare?by?the?priority?*/?
 ??public?int?compare(Object?o1,?Object?o2) {?
 ????for(Iterator?iterator?=?comparators.iterator();?iterator.hasNext();) {?
??????Comparator?comparator?=?(Comparator)iterator.next();?

??????int?result?=?comparator.compare(o1,?o2);?

 ??????if(result?!=?0) {?
????????return?result;?
??????}?
????}?

????return?0;?
??}?
}?

3.5 Comparator的組合應用 這一節講述上面兩個類的用法。 對應前面的排序問題,我們只需要3個Comparator類: (1)Field1Comaprator; (2)Field2Comaprator; (3)Field3Comaprator。
下面舉例說明,如何組合這些Comparator實現不同的排序條件。 (1)order by field1, field2
java代碼:?
CompoiComparator?myComparator?=?new?CompoiComparator();?
myComparator.?addComparators(?
 new?Comparator[] {new?Field1Comaprator?(),??new?Field2Comaprator?()};?
);?

//?records?is?a?list?of?Record?
Collections.sort(records,??myComparator);?
(2)order by field1 desc, field2
java代碼:?
CompoiComparator?myComparator?=?new?CompoiComparator();?
myComparator.?addComparators(?
 new?Comparator[] {?
new?ReverseComparator(new?Field1Comaprator?()),??
new?Field2Comaprator?()};?
);?

//?records?is?a?list?of?Record?
Collections.sort(records,??myComparator);?
這里提供的ReverseComparator類和CompositeComparator類都采用了Decorator Pattern。 CompositeComparator類同時也是Composite Pattern。
4.過濾條件的排列組合 (多謝shinwell指正,我改正了后面的代碼)
過濾條件問題也屬于條件組合問題的范疇。比如JDK提供的java.io.File類提供了一個文件過濾方法listFile(FileFilter),用戶可以定制不同的FileFilter,實現不同的過濾條件,比如文件時間在某個范圍內;文件后綴名,文件名符合某種模式;是目錄,還是文件,等等。 同樣,我們可以應用上述的解決方法,實現靈活的過濾條件組合——用一個CompositeFilter類任意組合過濾條件,用一個ReverseFilter類作為排除條件。 4.1 CompositeFilter類的代碼
java代碼:?
import?java.io.FileFilter;?
import?java.io.File;?

import?java.util.Iterator;?
import?java.util.List;?
import?java.util.LinkedList;?

 public?class?CompositeFilter?implements?FileFilter? {?

 ??/**?*//**?in?the?filter?list,?every?condition?should?be?met.?*/?
??private?List?filters?=?new?LinkedList();?

 ??/**?*//**?get?the?filters,?you?can?manipulate?it?as?need.*/?
 ??public?List?getFilters() {?
????return?filters;?
??}?

 ??/**?*//**?add?a?batch?of?filters?to?the?condition?list?*/?
 ??public?void?addFilters(FileFilter[]?filterArray) {?
 ????if(filterArray?==?null) {?
??????return;?
????}?

 ????for(int?i?=?0;?i?<?filterArray.length;?i++) {?
??????filters.add(filterArray);?
????}?
??}?

 ??/**?*//**?must?meet?all?the?filter?condition?*/?
 ??public?boolean?accept(File?pathname)? {?
 ????for(Iterator?iterator?=?filters.iterator();?iterator.hasNext();) {?
??????FileFilter?filter?=?(FileFilter)iterator.next();?

??????boolean?result?=?filter.accept(pathname);?

??????//?if?any?condition?can?not?be?met,?return?false.?
 ??????if(result?==?false) {?
????????return?false;?
??????}?
????}?

????//?all?conditions?are?met,?return?true.?
????return?true;?
??}?
}?

4.2 ReverseFilter類的代碼 java代碼:?
import?java.io.FileFilter;?
import?java.io.File;?

 public?class?ReverseFilter?implements?FileFilter? {?
 ??/**?*//**?the?original?filter*/?
??private?FileFilter?originalFilter?=?null;?

 ??/**?*//**?constructor?takes?a?filter?as?parameter?*/?
 ??public?ReverseFilter(FileFilter?filter) {?
????originalFilter?=?filter;?
??}?

 ??/**?*//**?must?meet?all?the?filter?condition?*/?
 ??public?boolean?accept(File?pathname)? {?
??????return?!originalFilter.accept(pathname);?
??}?
}?

5.總結 本文講述了Design Pattern的分析和實踐,并闡述了一類條件組合問題的解決思路。 |