之前在 benjielin前辈的博客中看到“管道过滤器(Pipe-And-Filter)模式(http://bj007.blog.51cto.com/1701577/345677)”,当时将文章中运用到的组合模式(Composite)与我刚刚写过的装饰模式(Decorator)和职责链模式(Chainof Responsibility)混为一谈,并希望用这后面两个模式进行代码实现,+_+
现在觉得还是先把那文章中的组合模式给具体实现一下吧,具体的文字描述请看上面文章链接哦。
在我的代码中,我假设的需求是:给定多个条件(即过滤器),遍历一本字典中的所有单词,将同时符合所有条件的所有单词查询(过滤)出来。现假定需要过滤出“单词中同时包含a、b、cd字串,并且以"end”结尾,最后是单词的长度大于7”。
好了,看清了需求,得出类图如下:
- //字典
- classDictionary{
- //字典里面有好多单词
- privateArrayList<String>allWords;
- publicDictionary(ArrayList<String>allWords){
- this.allWords=allWords;
- }
- //获取字典中所有单词
- publicArrayList<String>getAllWords(){
- returnthis.allWords;
- }
- }
- //过滤器接口,只有match()方法
- interfaceIFilter{
- publicbooleanmatch(Stringword);
- }
- //树叶型过滤器,过滤单词中长度大于指定长度
- classLengthFilterimplementsIFilter{
- privateintlength;
- publicLengthFilter(intlength){
- this.length=length;
- }
- @Override
- publicbooleanmatch(Stringword){
- if(word.length()>length){
- returntrue;
- }
- returnfalse;
- }
- }
- //树叶型过滤器,过滤单词中包含有某个字符字串
- classContainsFilterimplementsIFilter{
- privateStringsubStr;
- publicContainsFilter(StringsubStr){
- this.subStr=subStr;
- }
- @Override
- publicbooleanmatch(Stringword){
- if(word.contains(subStr)){
- returntrue;
- }
- returnfalse;
- }
- }
- //树叶型过滤器,过滤单词中以某个字符字串结束
- classEndFilterimplementsIFilter{
- privateStringsubStr;
- publicEndFilter(StringsubStr){
- this.subStr=subStr;
- }
- @Override
- publicbooleanmatch(Stringword){
- if(word.endsWith(subStr)){
- returntrue;
- }
- returnfalse;
- }
- }
- //抽象组合型过滤器,类似于树枝节点
- abstractclassCompositeFilterimplementsIFilter{
- protectedArrayList<IFilter>filters;
- publicCompositeFilter(){
- this.filters=newArrayList<IFilter>();
- }
- //继续将IFilter接口中的match()声明为abstract,
- //由具体的过滤器子类进行实现
- publicabstractbooleanmatch(Stringword);
- //添加过滤器链
- publicvoidaddFilters(ArrayList<IFilter>filters){
- this.filters.addAll(filters);
- }
- //添加一个过滤器
- publicvoidaddFilter(IFilterfilter){
- this.filters.add(filter);
- }
- //既然是树枝过滤器,其下必有子过滤器
- publicArrayList<IFilter>getFilters(){
- returnthis.filters;
- }
- }
- //and过滤器,树枝型过滤器
- classAndFilterextendsCompositeFilter{
- @Override
- publicbooleanmatch(Stringword){
- for(IFilterfilter:super.filters){
- if(!(filter.match(word))){
- returnfalse;
- }
- }
- returntrue;
- }
- }
- //or过滤器,树枝型过滤器
- classOrFilterextendsCompositeFilter{
- @Override
- publicbooleanmatch(Stringword){
- for(IFilterfilter:super.filters){
- if(filter.match(word)){
- returntrue;
- }
- }
- returnfalse;
- }
- }
- //管道
- classPipe{
- //字典,相当于流入管道的数据流
- privateDictionarydictionary;
- //用于保存过滤后的最终数据
- privateLinkedHashSet<String>theWords;
- //单词查询中需要用到的过滤器树
- privateIFilterfilterTree;
- //用于保存字典中的所有单词,即数据流中的一个个数据
- privateArrayList<String>allWords;
- publicPipe(Dictionarydictionary,IFilterfilterTree){
- this.dictionary=dictionary;
- this.filterTree=filterTree;
- this.theWords=newLinkedHashSet<String>();
- }
- publicLinkedHashSet<String>getWords(){
- //先搜索过滤字典中所有单词,再返回符合要求的单词集合
- this.allWords=dictionary.getAllWords();
- this.findWords();
- returnthis.theWords;
- }
- privatevoidfindWords(){
- //对每个单词进行过滤
- for(Stringword:allWords){
- if(filterTree.match(word)==true){
- this.theWords.add(word);
- }
- }
- }
- }
- //测试类
- publicclassClient{
- publicstaticvoidmain(String[]args){
- //创建过滤器树:包含"a"、"b"、"cd"子串,以"end"结尾,长度>7
- //同时包含"a"、"b"、"cd"子串的过滤器
- CompositeFilterandFilter=newAndFilter();
- IFiltercontain01=newContainsFilter("a");
- IFiltercontain02=newContainsFilter("b");
- IFiltercontain03=newContainsFilter("cd");
- andFilter.addFilter(contain01);
- andFilter.addFilter(contain02);
- andFilter.addFilter(contain03);
- //以"end"或"END"结尾的过滤器
- CompositeFilterorFilter=newOrFilter();
- IFilterend01=newEndFilter("end");
- IFilterend02=newEndFilter("END");
- orFilter.addFilter(end01);
- orFilter.addFilter(end02);
- //长度>7的过滤器
- IFilterlengthFilter=newLengthFilter(7);
- //构建过滤器树,用根过滤器将上面的所有过滤器组合起来
- CompositeFilterrootFilter=newAndFilter();
- rootFilter.addFilter(andFilter);
- rootFilter.addFilter(orFilter);
- rootFilter.addFilter(lengthFilter);
- //自定义一本字典里的所有单词
- ArrayList<String>allWords=newArrayList<String>();
- allWords.add("akkkk");
- allWords.add("ab--b-cd--end");
- allWords.add("abckk");
- allWords.add("abdcend");//长度为6,不符合
- allWords.add("kakbkck");
- allWords.add("a-b-cd-END");
- allWords.add("bbcc");
- //自定义一本字典
- Dictionarydictionary=newDictionary(allWords);
- //将字典、过滤器树传入管道
- Pipepipe=newPipe(dictionary,rootFilter);
- //单词流在通过管道时被过滤,获取最终单词
- System.out.println(pipe.getWords());
- }
- }
测试结果:
- [ab--b-cd--end,a-b-cd-END]
如此一来,基本上解决了我在原来文章中的许多疑问(下面的是修改前的内容),根据 benjielin前辈的提示,修改了原来完全不合理的地方,可看评论哦。
话说回来,原来的代码也太乱了,原因就是我完全理解错了benjielin 前辈文章中关于组合模式中AndFilter 类、OrFilter类的用处,也完全没弄明白组合模式究竟用于何处,呼...
小结:
1、Pipe 类中过滤的代码少了很多,只是调用过滤器的match() 方法而已;
2、由 1 也相应地去除了由 Pipe类来判断对象属于树叶还是树枝类型的逻辑,消去了坏味道;
3、原文中利用递归遍历过滤器树的方法一点都不合理,完全应该去除,当初是因为没理清思路;
4、改变主意,不用 职责链模式 来实现管道过滤器模式了,因为现在我觉得那个模式应该实现不了 Composite 模式这样的功能,它最多也只能起到链 的作用。
我的相关文章:
组合模式(Composite)的安全模式与透明模式http://haolloyin.blog.51cto.com/1177454/347308
职责链模式(Chain ofResponsibility)的Java实现http://haolloyin.blog.51cto.com/1177454/342166