一、Java IO中的装饰器模式:
良好的设计模式可以更好的扩充,“开闭原则”是指对新功能开放,对原有代码封闭。我理解为纵向扩展,在尽量不改变原代码的前提下进行扩展新功能,典型的装饰器例子有java IO包中的大家耳熟能详的代码:
BufferedReader bufReader=new BufferedReader(new InputStreamReader(new FileInputStream(new File("test.txt"))));
我们看上面的一句代码,
FileInputStream对new File("text.txt")进行了装饰!
InputStreamReader对FileInputStream进行了装饰!
BufferedReader对InputStreamReader进行了装饰!
我们假设现在对一个文件全部转换成 小写 字母,那么我们需要构购一个,那么上述的代码可
以改成:
BufferedReader bufReader=new BufferedReader(new InputStreamReader(new FileInputStream(new FileLowCaseStream(new File("test.txt")))));
二、我们的应用:
大家都用过51Job找过工作吧,假设现在找工作的Server业务层里有这几个搜索
1)前缀搜索:如有公司名为“腾迅网络”,那么,应该支持用户输入“腾迅”。(PrefixQuery)
2)准确搜索:搜索关键字为“java”(TermQuery)
3)范围搜索:搜索“某天到某到”,(RangeQuery)
4)模糊搜索:通过公司地址,“深圳”,也能搜索到“腾迅网络”(FuzzyQuery)
三、代码如下:
1)构建一个BaseQuery,主要提供类型一致,它是一个抽象类。
public abstract class BaseQuery {
public abstract BooleanQuery getQuery();
}
2)构建SearchQuery,它是我们上面提到的四种搜索的父类。
public abstract class SearchQuery extends BaseQuery {
protected BaseQuery baseQuery;
public abstract Query setQuery();
@Override
public BooleanQuery getQuery() {
BooleanQuery booleanQuery;
if (null == baseQuery)
booleanQuery = new BooleanQuery();
else
booleanQuery = baseQuery.getQuery() == null ? new BooleanQuery()
: baseQuery.getQuery();
Query query = setQuery();
booleanQuery.add(query, Occur.MUST);
return booleanQuery;
}
}
3)分别构建上面四种搜索:
public class FuzzyTemplateQuery extends SearchQuery {
protected String queryValue;
protected String attribute;
@Override
public Query setQuery() {
return new FuzzyQuery(new Term(attribute,queryValue));
}
}
上面代码,attribute是存进索引的键,queryValue是客户端输入的搜索的值。
同样的,构建其它三另的搜索只需重载一下setQuery即可,下面一并给出代码:
//前缀搜索,PrefixQuery
@Override
public Query setQuery() {
return new PrefixQuery(new Term(attribute,queryValue));
}
//准确搜索 TermQuery
@Override
public TermQuery setQuery() {
return new TermQuery(new Term(attribute,queryValue));
}
//范围搜索,RangeQuery,注意范围搜索有起始值和结束值
@Override
public Query setQuery() {
Term start = new Term(attribute,startValue);
Term end = new Term(attribute,endValue);
Query rangeQuery = new RangeQuery(start,end,bound);
return rangeQuery;
}
//针对RangeQuery我们还可以加上边界的设定
public BaseQuery setBound(boolean bound) {
this.bound = bound;
return this;
}
四、通过四种类型构造查询,如查找公司名称,它继承自PrefixTemplateQuery
public class CorporationQuery extends prefixQuery {
public CompanyQuery(String queryValue, BaseQuery baseQuery) {
this.attribute = "companyField";//设置索引中的key
this.queryValue = queryValue;
this.baseQuery = baseQuery;
}
}
其实做到这一步,就已经很容易了,只需要一个构造函数完成值的设置就行了。其它的就不举例了。分别继承再设值就好了。
五、写客户端的代码。
BaseQuery base = new CorporationQuery("腾讯",null);
那如果同时要查询腾讯公司的java职位呢?
BaseQuery base = new CorporationQuery("腾讯",null);
base = new JobQuery("java",base);
我们注意到,先构建一个query,搜索“腾讯”公司的,然后再构建JobQuery来装饰CorporationQuery。
至此我们完成了装饰器来动态增加搜索,尊循了开闭原则。