在一個較爲複雜的業務流程中,某些條件的滿足與否決定了業務邏輯的走向,我們可以把這些條件抽離出來,使得任意個條件以某種關係進行組合,從而靈活地對業務邏輯進行定製。另外,在查詢、過濾等應用場合中,我們也可以預定義多個條件,使用這些條件的組合來處理查詢邏輯,而不是使用邏輯判斷語句來處理,那樣只會讓代碼變得複雜,讓腦袋變大。
在Specification設計模式中,一個條件就是一個specification,多個specification通過串聯的方式以某種邏輯關係形成一個組合式的specification。首先看一下整體的UML圖:
下面是Specification接口的聲明:
public interface Specification {
boolean isSatisfiedBy(Object params);
Specification and(Specification other);
Specification or(Specification other);
Specification not();
}
它定義了各個條件間可用的關係:與、或、非,這三個關係所對應方法的返回值都是Specification自身,目的是爲了實現Specification之間的串聯(chaining),從而形成一個關係表達式,後面會看到具體的用法。isSatisfiedBy就是判定方法,參數是一個Object,支持任意類型。
下面我們來看CompositSpecification的聲明:
public abstract class CompositeSpecification implements Specification{
@Override
public Specification and(Specification other) {
return new AndSpecification(this, other);
}
public abstract boolean isSatisfiedBy(Object params);
@Override
public Specification not() {
return new NotSpecification(this);
}
@Override
public Specification or(Specification other) {
return new OrSpecification(this, other);
}
}
它實現了Specification接口的關係判定方法,而isSatisfiedBy則仍是抽象方法,需要派生類來具體實現。下面是三個分別實現了與、或、非關係判定的派生類的聲明:
public class AndSpecification extends CompositeSpecification {
private final Specification b;
private final Specification a;
public AndSpecification(Specification a,Specification b) {
this.a = a;
this.b = b;
}
@Override
public boolean isSatisfiedBy(Object params) {
return a.isSatisfiedBy(params) && b.isSatisfiedBy(params);
}
}
public class OrSpecification extends CompositeSpecification {
private final Specification b;
private final Specification a;
public OrSpecification(Specification a, Specification b) {
this.a = a;
this.b = b;
}
@Override
public boolean isSatisfiedBy(Object params) {
return a.isSatisfiedBy(params) || b.isSatisfiedBy(params);
}
}
public class NotSpecification extends CompositeSpecification {
private final Specification a;
public NotSpecification(Specification a) {
this.a = a;
}
@Override
public boolean isSatisfiedBy(Object params) {
return !a.isSatisfiedBy(params);
}
}
這些類就構成了Specification模式的核心部分,下面我們來看一個例子:
先定義一個男人:
public class Men {
public String name; // 姓名
public boolean married; // 是否已婚
public int cars; // 擁有車的數量
public int houses; // 擁有房子的數量
public Men(String name,int cars, int houses, boolean married) {
this.name = name;
this.cars = cars;
this.houses = houses;
this.married = married;
}
}
然後定義選男人的幾個條件:
// 有車
public class HasCarsSpecification extends CompositeSpecification {
@Override
public boolean isSatisfiedBy(Object params) {
Men m = (Men)params;
return m.cars > 0;
}
}
// 有房
public class HasHousesSpecification extends CompositeSpecification {
@Override
public boolean isSatisfiedBy(Object params) {
Men m = (Men)params;
return m.houses > 0;
}
}
// 已婚
public class MarriedSpecification extends CompositeSpecification {
@Override
public boolean isSatisfiedBy(Object params) {
Men m = (Men)params;
return m.married;
}
}
好,下面有位女嘉賓開始選它心目中的男人了:
Men[] candidates = {
new Men("李精英", 1, 1, false),
new Men("王老五", 5, 3, true),
new Men("趙白領", 0, 1, false),
new Men("West_Link", 0, 0, false)
};
HasHousesSpecification hasHouse = new HasHousesSpecification();
HasCarsSpecification hasCar = new HasCarsSpecification();
MarriedSpecification married = new MarriedSpecification();
Specification spec = hasHouse.and(hasCar).and(married.not());
for (Men men : candidates) {
if(spec.isSatisfiedBy(men))
System.out.println(men.name);
}
從Specification spec = hasHouse.and(hasCar).and(married.not())這行代碼可以看出這位女嘉賓選擇了有車
並且有房的未婚男子,所以打印結果爲:李精英。
經過多輪選擇,West_Link始終沒有被選上!