規格模式
規格模式(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