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