1. 程式人生 > >設計模式實戰(一)——使用策略模式(strategy pattern)實現多關鍵字排序

設計模式實戰(一)——使用策略模式(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”就是呼叫不同演算法的類,在其內部根據不同需要選擇不同的演算法。有時需要將具象策略例項化後再傳給其它類,這時可以使用“簡單工廠”(
Simple Factory“工廠方法”(Factory Method生成所需的具象策略。下面就以我正在做的一個專案,簡化一下後說明一下策略模式的使用。

該專案是一個小型的商業網站,邏輯層由Servlet實現。使用者有一個需求,需要從資料庫調出商品資訊後能夠對記錄按名稱(name)、規格(standard)、價格(price)和註冊日期(register date)進行排序。雖然可以考慮按不同的排序關鍵字使用不同的sql語句(即不同的order by)查詢資料庫。但這樣做的網路資料流量太大,每次需要從資料庫完整地取回一個數據集(ResultSet),所以我選擇了將資料集一次取到客戶端的一個

List中,然後在客戶端按不同的關鍵字對List進行排序。

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是一個封裝了商品資訊的beanList中存放的就是這些beanItemSortItemComparator以及四個具體類實現了“簡單工廠”模式,並封裝了sort方法。

 


    下面是具體的程式碼(

StandardComparator類的程式碼與NameComparator類的程式碼大同小異,在這裡不列出):

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);// 呼叫StringCompareTo方法

}

}

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);// 呼叫DoubleCompareTo方法

}

}

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);// 呼叫DateCompareTo方法

}

}

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);// 按規格排序

}

}