规格模式是组合模式的一种扩展,在框架性开发中使用较多(项目级开发很少使用),这里做一个简单的介绍。由于是摘录,上下文章节可以参考我的博客,http://hi.baidu.com/cbf4life,或者下载PDF文件也一样。 发带格式、带图片的DOC文档太麻烦了,刚刚还出现了内容都整理好了,然后附件上传不上来,就在那转圈,我晕,只有重新发了!
这里假设了一个这样一个场景,有一堆的User对象,UserProvider提供查询服务。们来看组合规格书(CompositeSpecification),它是一个抽象类,实现了与或非的操作,如下所示。
public abstract class CompositeSpecification implements IUserSpecification {
//是否满足条件有实现类实现
public abstract boolean isSatisfiedBy(User user);
//and操作
public IUserSpecification and(IUserSpecification spec) {
return new AndSpecification(this,spec);
}
//not操作
public IUserSpecification not() {
return new NotSpecification(this);
}
//or操作
public IUserSpecification or(IUserSpecification spec) {
return new OrSpecification(this,spec);
}
}
候选对象是否满足条件是由isSatisfiedBy方法决定的,它代表的是一个判断逻辑,由各个实现类实现。三个与或非操作在抽象类中实现,它是通过直接new了一个子类,如此设计非常符合单一职责原则,每个子类都有一个独立的职责,要么完成与操作,要么完成或操作,要么完成非操作。我们先来看与操作规格书,如下所示。
public class AndSpecification extends CompositeSpecification {
//传递两个规格书进行and操作
private IUserSpecification left;
private IUserSpecification right;
public AndSpecification(IUserSpecification _left,IUserSpecification _right){
this.left = _left;
this.right = _right;
}
//进行and运算
@Override
public boolean isSatisfiedBy(User user) {
return left.isSatisfiedBy(user) && right.isSatisfiedBy(user);
}
}
通过构造函数传递过来两个需要操作的规格书,然后通过isSatisfiedBy方法返回两者and操作结果。或规格书和非规格书与此类似,分别如下所示。
public class OrSpecification extends CompositeSpecification {
//左右两个规格书
private IUserSpecification left;
private IUserSpecification right;
public OrSpecification(IUserSpecification _left,IUserSpecification _right){
this.left = _left;
this.right = _right;
}
//or运算
@Override
public boolean isSatisfiedBy(User user) {
return left.isSatisfiedBy(user) || right.isSatisfiedBy(user);
}
}
public class NotSpecification extends CompositeSpecification {
//传递一个规格书
private IUserSpecification spec;
public NotSpecification(IUserSpecification _spec){
this.spec = _spec;
}
//not操作
@Override
public boolean isSatisfiedBy(User user) {
return !spec.isSatisfiedBy(user);
}
}
该三个规格书都是不发生变化的,只要使用该框架,三个规格书都要实现的,而且代码基本上是雷同的,所以才有了父类依赖子类的设计,否则是严禁出现父类依赖子类的情况。大家再仔细看看这三个规格书和组合规格书,代码很简单,但也很巧妙,它跳出了我们面向对象设计的思维,不变部分使用一种固化方式实现。
public class UserByNameEqual extends CompositeSpecification {
//基准姓名
private String name;
//构造函数传递基准姓名
public UserByNameEqual(String _name){
this.name = _name;
}
//检验用户是否满足条件
public boolean isSatisfiedBy(User user) {
return user.getName().equals(name);
}
}
仅仅修改了黑体部分,其他没有任何改变。另外两个规格书修改相同,不再赘述。其他的User及UserProvider没有任何改动,不再赘述。
public class Client {
public static void main(String[] args) {
//首先初始化一批用户
ArrayList<User> userList = new ArrayList<User>();
userList.add(new User("苏国庆",23));
userList.add(new User("国庆牛",82));
userList.add(new User("张国庆三",10));
userList.add(new User("李四",10));
//定义一个用户查询类
IUserProvider userProvider = new UserProvider(userList);
//打印出名字包含国庆的人员
System.out.println("===名字包含国庆的人员===");
//定义一个规格
IUserSpecification spec = new UserByAgeThan(25);
IUserSpecification spec2 = new UserByNameLike("%国庆%");
for(User u:userProvider.findUser(spec.and(spec2))){
System.out.println(u);
}
}
}
===名字包含国庆的人员===
用户名:国庆牛 年龄:82