新設計模式——規格模式

規格模式

規格模式(Specification Pattern):它是組合模式的一種特殊應用。同時,每個規格書都是一個策略,它完成了一系列邏輯的封裝。

抽象規格書ISpecification:

public interface ISpecification {
    //候選者是否滿足要求 
    public boolean isSatisfiedBy(Object candidate); 
    //and操作 
    public ISpecification and(ISpecification spec); 
    //or操作 
    public ISpecification or(ISpecification spec); 
    //not操作 
    public ISpecification not(); 
}

組合規格書CompositeSpecification:

public abstract class CompositeSpecification implements ISpecification { 
    //是否滿足條件由實現類實現 
    public abstract boolean isSatisfiedBy(Object candidate); 
    //and操作 
    public ISpecification and(ISpecification spec) { 
        return new AndSpecification(this,spec); 
    }
    //not操作 
    public ISpecification not() { 
        return new NotSpecification(this); 
    }
    //or操作 
    public ISpecification or(ISpecification spec) { 
        return new OrSpecification(this,spec); 
    } 
} 

與規格書AndSpecification:

public class AndSpecification extends CompositeSpecification { 
    //傳遞兩個規格書進行and操作 
    private ISpecification left; 
    private ISpecification right; 
    public AndSpecification(ISpecification _left,ISpecification _right){ 
        this.left = _left; 
        this.right = _right; 
    }
    //進行and運算 
    @Override 
    public boolean isSatisfiedBy(Object candidate) { 
        return left.isSatisfiedBy(candidate) && right.isSatisfiedBy(candidate); 
    } 
} 

或規格書OrSpecification:

public class OrSpecification extends CompositeSpecification { 
    //左右兩個規格書 
    private ISpecification left; 
    private ISpecification right; 
    public OrSpecification(ISpecification _left,ISpecification _right){ 
        this.left = _left; 
        this.right = _right; 
    }
    //or運算 
    @Override 
    public boolean isSatisfiedBy(Object candidate) { 
        return left.isSatisfiedBy(candidate) || right.isSatisfiedBy(candidate); 
    } 
} 

非規格書NotSpecification:

public class NotSpecification extends CompositeSpecification { 
    //傳遞一個規格書 
    private ISpecification spec; 
    public NotSpecification(ISpecification _spec){ 
        this.spec = _spec; 
    }
    //not操作 
    @Override 
    public boolean isSatisfiedBy(Object candidate) { 
        return !spec.isSatisfiedBy(candidate); 
    } 
} 

業務規格書BizSpecification:

public class BizSpecification extends CompositeSpecification { 
    //基準對象 
    private Object obj; 
    public BizSpecification(Object _obj){ 
        this.obj = _obj; 
    }
    @Override 
    public boolean isSatisfiedBy(Object candidate) { 
        //根據基準對象和候選對象,進行業務判斷,返回boolean 
        return false; 
    } 
} 
public class Client { 
    public static void main(String[] args) { 
        //待分析的對象 
        ArrayList<Object> list = new ArrayList<Object>(); 
        //定義兩個業務規格書 
        ISpecification spec1 = new BizSpecification(new Object()); 
        ISpecification spec2 = new BizSpecification(new Object()); 
        //規則的調用 
        for(Object obj:list){ 
            if(spec1.and(spec2).isSatisfiedBy(obj)){ //and操作 
                System.out.println(obj); 
            } 
        } 
    } 
} 

規格模式的實例

查找出姓名中包含國慶”兩個字的用戶,這在關係型數據庫中很容易實現,但是在對象羣中怎麼實現這樣的查詢呢?

public class User {
	private String name;
	private int age;
	public User(String name, int age) {
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	//用戶信息打印
	@Override
	public String toString() {
		return "用戶名:" + name + "\t年齡:" + age;
	}
}
import java.util.ArrayList;
import com.sfq.action.User;
public interface IUserProvider {
	//根據條件查找用戶
	public ArrayList<User> findUser(IUserSpecification userSpec);
}
import java.util.ArrayList;
import com.sfq.impl.IUserProvider;
import com.sfq.impl.IUserSpecification;
public class UserProvider implements IUserProvider {
	//用戶列表
	private ArrayList<User> userList;	
	public UserProvider(ArrayList<User> userList) {
		this.userList = userList;
	}
	@Override
	public ArrayList<User> findUser(IUserSpecification userSpec) {
		ArrayList<User> result = new ArrayList<User>();
		for(User u:userList) {
			if (userSpec.isSatisfiedBy(u)) {
				result.add(u);
			}
		}
		return result;
	}
}

 

import com.sfq.action.User;
public interface IUserSpecification {
	//候選者是否滿足要求
	public boolean isSatisfiedBy(User user);
	public IUserSpecification and(IUserSpecification spec);//與
	public IUserSpecification or(IUserSpecification spec);//或
	public IUserSpecification not();//非
}
import com.sfq.action.AndSpecification;
import com.sfq.action.NotSpecification;
import com.sfq.action.OrSpecification;
import com.sfq.action.User;
public abstract class CompositeSpecification implements IUserSpecification {
	public abstract boolean isSatisfiedBy(User user);
	@Override
	public IUserSpecification and(IUserSpecification spec) {
		return new AndSpecification(this,spec);
	}
	@Override
	public IUserSpecification or(IUserSpecification spec) {
		return new OrSpecification(this,spec);
	}
	@Override
	public IUserSpecification not() {
		return new NotSpecification(this);
	}
}
//and
import com.sfq.impl.CompositeSpecification;
import com.sfq.impl.IUserSpecification;
public class AndSpecification extends CompositeSpecification implements IUserSpecification {
	//傳遞兩個規格書進行and操作
	private IUserSpecification left;
	private IUserSpecification right;
	public AndSpecification(IUserSpecification left, IUserSpecification right) {
		this.left = left;
		this.right = right;
	}
	@Override
	public boolean isSatisfiedBy(User user) {
		return left.isSatisfiedBy(user) && right.isSatisfiedBy(user);
	}
}
//or
import com.sfq.impl.CompositeSpecification;
import com.sfq.impl.IUserSpecification;
public class OrSpecification extends CompositeSpecification implements IUserSpecification {
	private IUserSpecification left;
	private IUserSpecification right;
	public OrSpecification(IUserSpecification left, IUserSpecification right) {
		this.left = left;
		this.right = right;
	}
	@Override
	public boolean isSatisfiedBy(User user) {
		return left.isSatisfiedBy(user) || right.isSatisfiedBy(user);
	}
}
//not
import com.sfq.impl.CompositeSpecification;
import com.sfq.impl.IUserSpecification;
public class NotSpecification extends CompositeSpecification implements IUserSpecification {
	private IUserSpecification spec;
	public NotSpecification(IUserSpecification spec) {
		this.spec = spec;
	}
	@Override
	public boolean isSatisfiedBy(User user) {
		return !spec.isSatisfiedBy(user);
	}
}
import com.sfq.impl.CompositeSpecification;
public class UserByNameEqual extends CompositeSpecification {
	//基準姓名
	private String name;
	public UserByNameEqual(String name) {
		this.name = name;
	}
	//驗證用戶是否滿足條件
	@Override
	public boolean isSatisfiedBy(User user) {
		return user.getName().equals(name);
	}
}
import com.sfq.impl.CompositeSpecification;
public class UserByNameLike extends CompositeSpecification {
	//like的標記 
	private final static String LIKE_FLAG = "%"; 
	//基準的like字符串 
	private String likeStr; 
	//構造函數傳遞基準姓名 
	public UserByNameLike(String _likeStr){ 
		this.likeStr = _likeStr; 
	}
	//檢驗用戶是否滿足條件 
	public boolean isSatisfiedBy(User user) { 
		boolean result = false; 
		String name = user.getName(); 
		//替換掉%後的乾淨字符串 
		String str = likeStr.replace("%",""); 
		//是以名字開頭,如'國慶%' 
		if(likeStr.endsWith(LIKE_FLAG) && !likeStr.startsWith(LIKE_FLAG)){ 
			result = name.startsWith(str); 
		}else if(likeStr.startsWith(LIKE_FLAG) && !likeStr.endsWith(LIKE_FLAG)){ 
			//類似 '%國慶' 
			result = name.endsWith(str); 
		}else{
			result = name.contains(str); 
			//類似於'%國慶%' 
		}
		return result; 
	}
}
import java.util.ArrayList;
import com.sfq.action.User;
import com.sfq.action.UserByNameLike;
import com.sfq.action.UserProvider;
import com.sfq.impl.IUserProvider;
import com.sfq.impl.IUserSpecification;
public class Client {
	public static void main(String[] args) {
		//初始化一批用戶
		ArrayList<User> userList = new ArrayList<User>();
		userList.add(new User("李國慶", 23));
		userList.add(new User("張國慶", 99));
		userList.add(new User("國慶五", 10));
		userList.add(new User("王大", 1));
		//定義用戶查找類
		IUserProvider userProvider = new UserProvider(userList);
		System.out.println("-----名字帶國慶的-----");
		//定義規格書
		IUserSpecification userSpec = new UserByNameLike("%國慶%");
		for(User u:userProvider.findUser(userSpec)) {
			System.out.println(u);
		}
	}
}

結果
-----名字帶國慶的-----
用戶名:李國慶	年齡:23
用戶名:張國慶	年齡:99
用戶名:國慶五	年齡:10

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章