設計模式實戰(一)——使用策略模式(strategy pattern)實現多關鍵字排序
“策略模式”的出現,是為了提供一套相互之間可靈活替換的演算法,在不影響上層介面的情況下,使用者可以自由選擇不同的演算法完成邏輯。
策略模式的UML示意圖如下:<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />
其中演算法的模型介面在“抽象策略”中定義,各具象策略實現不同的策略。“消費API”就是呼叫不同演算法的類,在其內部根據不同需要選擇不同的演算法。有時需要將具象策略例項化後再傳給其它類,這時可以使用“簡單工廠”(該專案是一個小型的商業網站,邏輯層由Servlet實現。使用者有一個需求,需要從資料庫調出商品資訊後能夠對記錄按名稱(name)、規格(standard)、價格(price)和註冊日期(register date)進行排序。雖然可以考慮按不同的排序關鍵字使用不同的sql語句(即不同的order by)查詢資料庫。但這樣做的網路資料流量太大,每次需要從資料庫完整地取回一個數據集(ResultSet),所以我選擇了將資料集一次取到客戶端的一個
java.util.Collections類中有一個public static void sort(List list, Comparator comparator)的方法,可以按照不同的Comparator物件對list進行排序,它使用的是快速排序,所以效率非常高。而java.util.Comparator是一個介面:
package java.util;
public abstract interface Comparator {
boolean equals(Object object);
int compare(Object object, Object object1);
}
其中和排序有關的是compare方法,它返回一個整數,若第一個引數比第二個引數“大”,則返回一個正數,若“小”則返回一個負數,若“相等”則返回0,這裡的“大”、“小”、“相等”是由compare方法具體實現定義的一種比較標準。由這個方法不禁想到C語言中qsort函式中使用的函式指標int *compare(*,*),JAVA中之所以沒有函式指標,就是用介面取代了(更詳細的介紹見《Effective Java》中第22條“用類和介面來代替函式指標”)。
很明顯,Comparator介面就是我們的“抽象策略”,sort方法就是我們的“消費API”,而不同的“具象策略”就是我們從Comparator介面實現的根據不同關鍵字排序的類。
整個排序模型的UML圖如下,其中為了作圖方便,我從Comparator繼承了一個介面ItemComparator,根據不同的關鍵字從ItemComparator介面泛化了NameComparator類,PriceComparator類,RegisterDateComparator類和StandardComparator類。實際運用中不需要這個介面,四個類可以直接從Comparator泛化。ItemBean是一個封裝了商品資訊的bean,List中存放的就是這些bean。ItemSort和ItemComparator以及四個具體類實現了“簡單工廠”模式,並封裝了sort方法。
下面是具體的程式碼(
NameComparator類:
package com.lim.designpatterns.strategy;
public class NameComparator
implements ItemComparator{
NameComparator(){}// 將構造器封裝,包外的類欲得到Comparator例項只能通過簡單工廠
public int compare(Object o1,Object o2){
String name1=((ItemBean)o1).getName();
String name2=((ItemBean)o2).getName();
return name1.compareTo(name2);// 呼叫String的CompareTo方法
}
}
PriceComparator類
package com.lim.designpatterns.strategy;
public class PriceComparator
implements ItemComparator{
PriceComparator(){}
public int compare(Object o1,Object o2){
Double price1=new Double(((ItemBean)o1).getPrice());
Double price2=new Double(((ItemBean)o2).getPrice());
return price1.compareTo(price2);// 呼叫Double的CompareTo方法
}
}
RegisterDateComparator類
package com.lim.designpatterns.strategy;
import java.util.*
;
public class RegisterDateComparator
implements ItemComparator{
RegisterDateComparator(){}
public int compare(Object o1,Object o2){
Date date1=((ItemBean)o1).getRegisterDate();
Date date2=((ItemBean)o2).getRegisterDate();
return date1.compareTo(date2);// 呼叫Date的CompareTo方法
}
}
ItemSort類
package com.lim.designpatterns.strategy;
import java.util.*;
public class ItemSort{
public static List sort(List items,ItemComparator c){
Collections.sort(items,c);
return items;
}
public static final ItemComparator NAME=new NameComparator();// 簡單工廠
public static final ItemComparator PRICE=new PriceComparator();
public static final ItemComparator STANDARD=new StandardComparator();
public static final ItemComparator REG_DATE=new RegisterDateComparator();
}
TestItemSort類
package com.lim.designpatterns.strategy;
import java.util.*;
public class TestItemSort{
public static void main(String[] args){
List items=new ArrayList();
// 向List新增條目
items=ItemSort.sort(items,ItemSort.NAME);// 按名稱排序
items=ItemSort.sort(items,ItemSort.PRICE);// 按價格排序
items=ItemSort.sort(items,ItemSort.REG_DATE);// 按註冊日期排序
items=ItemSort.sort(items,ItemSort.STANDARD);// 按規格排序
}
}