設計模式之規(guī)格模式(Specification Pattern)
1 規(guī)格模式的定義
規(guī)格模式(Specification Pattern)可以認為是組合模式的一種擴展。很多時候程序中的某些條件決定了業(yè)務邏輯,這些條件就可以抽離出來以某種關系(與、或、非)進行組合,從而靈活地對業(yè)務邏輯進行定制。另外,在查詢、過濾等應用場合中,通過預定義多個條件,然后使用這些條件的組合來處理查詢或過濾,而不是使用邏輯判斷語句來處理,可以簡化整個實現(xiàn)邏輯。這里的每個條件都是一個規(guī)格,多個規(guī)格(條件)通過串聯(lián)的方式以某種邏輯關系形成一個組合式的規(guī)格。規(guī)格模式屬于結(jié)構(gòu)型設計模式。
2 規(guī)格模式的應用場景
規(guī)格模式主要適用于以下應用場景。
(1)驗證對象,檢驗對象本身是否滿足某些業(yè)務要求或者是否已經(jīng)為實現(xiàn)某個業(yè)務目標做好了準備。
(2)從集合中選擇符合特定業(yè)務規(guī)則的對象或?qū)ο笞蛹?/p>
(3)指定在創(chuàng)建新對象的時候必須要滿足某種業(yè)務要求。
3 規(guī)格模式的UML類圖
規(guī)格模式的UML類圖如下圖所示。
由上圖可以看到,規(guī)格模式主要包含6個角色。
(1)抽象規(guī)格書(Specification):對規(guī)格書的抽象定義。
(2)組合規(guī)格書(CompositeSpecification):一般設計為抽象類,對規(guī)格書進行與或非操作,實現(xiàn)and()、or()、not()方法,在方法中關聯(lián)子類,因為子類為固定類,所以父類可以進行關聯(lián)。
(3)與規(guī)格書(AndSpecification):對規(guī)格書進行與操作,實現(xiàn)isSatisfiedBy()方法。
(4)或規(guī)格書(OrSpecification):對規(guī)格書進行或操作,實現(xiàn)isSatisfiedBy()方法。
(5)非規(guī)格書(NotSpecification):對規(guī)格書進行非操作,實現(xiàn)isSatisfiedBy()方法。
(6)業(yè)務規(guī)格書(BizSpecification):實現(xiàn)isSatisfiedBy()方法,對業(yè)務進行判斷,一個類為一種判斷方式,可進行擴展。
4 規(guī)格模式的通用寫法
以下是規(guī)格模式的通用寫法。
- public class Client {
- public static void main(String[] args) {
- //待分析的對象
- List<Object> list = new ArrayList<Object>();
- //定義兩個業(yè)務規(guī)格書
- ISpecification spec1 = new BizSpecification("a");
- ISpecification spec2 = new BizSpecification("b");
- //規(guī)格調(diào)用
- for (Object o : list) {
- if(spec1.and(spec2).isSatisfiedBy(o)){ //如果o滿足spec1 && spec2
- System.out.println(o);
- }
- }
- }
- //抽象規(guī)格書
- interface ISpecification {
- //候選者是否滿足條件
- boolean isSatisfiedBy (Object candidate) ;
- //and操作
- ISpecification and (ISpecification spec);
- //or操作
- ISpecification or (ISpecification spec);
- //not操作
- ISpecification not ();
- }
- //組合規(guī)格書
- static abstract class CompositeSpecification implements ISpecification {
- //是否滿足條件由子類實現(xiàn)
- public abstract boolean isSatisfiedBy (Object candidate) ;
- //and操作
- public ISpecification and (ISpecification spec) {
- return new AndSpecification(this, spec);
- }
- //or操作
- public ISpecification or(ISpecification spec) {
- return new OrSpecification(this, spec);
- }
- //not操作
- public ISpecification not() {
- return new NotSpecification(this);
- }
- }
- //與規(guī)格書
- static class AndSpecification extends CompositeSpecification {
- //傳遞兩個規(guī)格書進行and操作
- private ISpecification left;
- private ISpecification right;
- public AndSpecification(ISpecification left, ISpecification right) {
- this.left = left;
- this.right = right;
- }
- //進行and運算
- public boolean isSatisfiedBy(Object candidate) {
- return left.isSatisfiedBy(candidate) && right.isSatisfiedBy(candidate);
- }
- }
- static class OrSpecification extends CompositeSpecification {
- //傳遞兩個規(guī)格書進行or操作
- private ISpecification left;
- private ISpecification right;
- public OrSpecification(ISpecification left, ISpecification right) {
- this.left= left;
- this.right = right;
- }
- //進行or運算
- public boolean isSatisfiedBy(Object candidate) {
- return left.isSatisfiedBy(candidate) || right.isSatisfiedBy(candidate);
- }
- }
- static class NotSpecification extends CompositeSpecification {
- //傳遞兩個規(guī)格書進行非操作
- private ISpecification spec;
- public NotSpecification(ISpecification spec) {
- this.spec = spec;
- }
- //進行not運算
- public boolean isSatisfiedBy(Object candidate) {
- return !spec.isSatisfiedBy(candidate);
- }
- }
- //業(yè)務規(guī)格書
- static class BizSpecification extends CompositeSpecification {
- //基準對象,如姓名等,也可以是int等類型
- private String obj;
- public BizSpecification(String obj) {
- this.obj = obj;
- }
- //判斷是否滿足要求
- public boolean isSatisfiedBy(Object candidate){
- //根據(jù)基準對象判斷是否符合
- return true;
- }
- }
- }
5 規(guī)格模式的優(yōu)點
規(guī)格模式非常巧妙地實現(xiàn)了對象篩選功能,適合在多個對象中篩選查找,或者業(yè)務規(guī)則不適于放在任何已有實體或值對象中,而且規(guī)則變化和組合會掩蓋對象的基本含義的情況。
6 規(guī)格模式的缺點
規(guī)格模式中有一個很嚴重的問題就是父類依賴子類,這種情景只有在非常明確不會發(fā)生變化的場景中存在,它不具備擴展性,是一種固化而不可變化的結(jié)構(gòu)。一般在面向?qū)ο笤O計中應該盡量避免。