GoF著作中未提到的設計模式(6):Specification

在一個較爲複雜的業務流程中,某些條件的滿足與否決定了業務邏輯的走向,我們可以把這些條件抽離出來,使得任意個條件以某種關係進行組合,從而靈活地對業務邏輯進行定製。另外,在查詢、過濾等應用場合中,我們也可以預定義多個條件,使用這些條件的組合來處理查詢邏輯,而不是使用邏輯判斷語句來處理,那樣只會讓代碼變得複雜,讓腦袋變大。

  在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始終沒有被選上!

發佈了27 篇原創文章 · 獲贊 20 · 訪問量 35萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章