之前在 benjielin 前辈的博客中看到“管道过滤器(Pipe-And-Filter)模式(http://bj007.blog.51cto.com/1701577/345677)”,当时将文章中运用到的组合模式(Composite)与我刚刚写过的装饰模式(Decorator)和职责链模式(Chain of Responsibility)混为一谈,并希望用这后面两个模式进行代码实现,+_+

现在觉得还是先把那文章中的组合模式给具体实现一下吧,具体的文字描述请看上面文章链接哦。

在我的代码中,我假设的需求是:给定多个条件(即过滤器),遍历一本字典中的所有单词,将同时符合所有条件的所有单词查询(过滤)出来。现假定需要过滤出“单词中同时包含a、b、cd字串,并且以"end”结尾,最后是单词的长度大于7 ”。

好了,看清了需求,得出类图如下:

  1. // 字典
  2. class Dictionary {
  3. // 字典里面有好多单词
  4. private ArrayList<String> allWords;
  5. public Dictionary(ArrayList<String> allWords) {
  6. this.allWords = allWords;
  7. }
  8. // 获取字典中所有单词
  9. public ArrayList<String> getAllWords() {
  10. return this.allWords;
  11. }
  12. }
  1. // 过滤器接口,只有 match() 方法
  2. interface IFilter {
  3. public boolean match(String word);
  4. }
  1. // 树叶型过滤器,过滤单词中长度大于指定长度
  2. class LengthFilter implements IFilter {
  3. private int length;
  4. public LengthFilter(int length) {
  5. this.length = length;
  6. }
  7. @Override
  8. public boolean match(String word) {
  9. if (word.length() > length) {
  10. return true;
  11. }
  12. return false;
  13. }
  14. }
  1. // 树叶型过滤器,过滤单词中包含有某个字符字串
  2. class ContainsFilter implements IFilter {
  3. private String subStr;
  4. public ContainsFilter(String subStr) {
  5. this.subStr = subStr;
  6. }
  7. @Override
  8. public boolean match(String word) {
  9. if (word.contains(subStr)) {
  10. return true;
  11. }
  12. return false;
  13. }
  14. }
  1. // 树叶型过滤器,过滤单词中以某个字符字串结束
  2. class EndFilter implements IFilter {
  3. private String subStr;
  4. public EndFilter(String subStr) {
  5. this.subStr = subStr;
  6. }
  7. @Override
  8. public boolean match(String word) {
  9. if (word.endsWith(subStr)) {
  10. return true;
  11. }
  12. return false;
  13. }
  14. }
  1. // 抽象组合型过滤器,类似于树枝节点
  2. abstract class CompositeFilter implements IFilter {
  3. protected ArrayList<IFilter> filters;
  4. public CompositeFilter() {
  5. this.filters = new ArrayList<IFilter>();
  6. }
  7. // 继续将 IFilter 接口中的 match() 声明为 abstract,  
  8.     // 由具体的过滤器子类进行实现
  9. public abstract boolean match(String word);
  10. // 添加过滤器链
  11. public void addFilters(ArrayList<IFilter> filters) {
  12. this.filters.addAll(filters);
  13. }
  14. // 添加一个过滤器
  15. public void addFilter(IFilter filter) {
  16. this.filters.add(filter);
  17. }
  18. // 既然是树枝过滤器,其下必有子过滤器
  19. public ArrayList<IFilter> getFilters() {
  20. return this.filters;
  21. }
  22. }
  1. // and 过滤器,树枝型过滤器
  2. class AndFilter extends CompositeFilter {
  3. @Override
  4. public boolean match(String word) {
  5. for(IFilter filter : super.filters) {
  6. if(!(filter.match(word))) {
  7. return false;
  8. }
  9. }
  10. return true;
  11. }
  12. }
  1. // or 过滤器,树枝型过滤器
  2. class OrFilter extends CompositeFilter {
  3. @Override
  4. public boolean match(String word) {
  5. for(IFilter filter : super.filters) {
  6. if(filter.match(word)) {
  7. return true;
  8. }
  9. }
  10. return false;
  11. }
  12. }
  1. // 管道
  2. class Pipe {
  3. // 字典,相当于流入管道的数据流
  4. private Dictionary dictionary;
  5. // 用于保存过滤后的最终数据
  6. private LinkedHashSet<String> theWords;
  7. // 单词查询中需要用到的过滤器树
  8. private IFilter filterTree;
  9. // 用于保存字典中的所有单词,即数据流中的一个个数据
  10. private ArrayList<String> allWords;
  11. public Pipe(Dictionary dictionary, IFilter filterTree) {
  12. this.dictionary = dictionary;
  13. this.filterTree = filterTree;
  14. this.theWords = new LinkedHashSet<String>();
  15. }
  16. public LinkedHashSet<String> getWords() {
  17. // 先搜索过滤字典中所有单词,再返回符合要求的单词集合
  18. this.allWords = dictionary.getAllWords();
  19. this.findWords();
  20. return this.theWords;
  21. }
  22. private void findWords() {
  23. // 对每个单词进行过滤
  24. for (String word : allWords) {
  25. if(filterTree.match(word) == true) {
  26. this.theWords.add(word);
  27. }
  28. }
  29. }
  30. }
  1. // 测试类
  2. public class Client {
  3. public static void main(String[] args) {
  4. // 创建过滤器树: 包含"a"、"b"、"cd"子串,以"end"结尾,长度 > 7
  5. // 同时包含"a"、"b"、"cd"子串的过滤器
  6. CompositeFilter andFilter = new AndFilter();
  7. IFilter contain01 = new ContainsFilter("a");
  8. IFilter contain02 = new ContainsFilter("b");
  9. IFilter contain03 = new ContainsFilter("cd");
  10. andFilter.addFilter(contain01);
  11. andFilter.addFilter(contain02);
  12. andFilter.addFilter(contain03);
  13. // 以 "end" 或 "END" 结尾的过滤器
  14. CompositeFilter orFilter = new OrFilter();
  15. IFilter end01 = new EndFilter("end");
  16. IFilter end02 = new EndFilter("END");
  17. orFilter.addFilter(end01);
  18. orFilter.addFilter(end02);
  19. // 长度 > 7 的过滤器
  20. IFilter lengthFilter = new LengthFilter(7);
  21. // 构建过滤器树,用根过滤器将上面的所有过滤器组合起来
  22. CompositeFilter rootFilter = new AndFilter();
  23. rootFilter.addFilter(andFilter);
  24. rootFilter.addFilter(orFilter);
  25. rootFilter.addFilter(lengthFilter);
  26. // 自定义一本字典里的所有单词
  27. ArrayList<String> allWords = new ArrayList<String>();
  28. allWords.add("akkkk");
  29. allWords.add("ab--b-cd--end");
  30. allWords.add("abckk");
  31. allWords.add("abdcend");// 长度为6,不符合
  32. allWords.add("kakbkck");
  33. allWords.add("a-b-cd-END");
  34. allWords.add("bbcc");
  35. // 自定义一本字典
  36. Dictionary dictionary = new Dictionary(allWords);
  37. // 将字典、过滤器树传入管道
  38. Pipe pipe = new Pipe(dictionary, rootFilter);
  39. // 单词流在通过管道时被过滤,获取最终单词
  40. System.out.println(pipe.getWords());
  41. }
  42. }

测试结果:

  1. [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 of Responsibility)的Java实现http://haolloyin.blog.51cto.com/1177454/342166

以下是修改前的部分内容,可不看,因为太不合理了。但我还是想保存着,毕竟是从以下代码修改而来的,所以可以参看benjielin前辈的评论来看。

类图如下:

代码如下:

//树叶型过滤器,直接实现 IFilter ,过滤单词中长度大于 7
class LengthFilter implements IFilter {@Overridepublic boolean match(String word) {if (word.length() > 7) {return true;}return false;}
}
// 抽象组合型过滤器,类似于树枝节点
abstract class CompositeFilter implements IFilter {private ArrayList<IFilter> filters;    // 需要被过滤的单词中的字串protected String subStr;public CompositeFilter(String subStr) {this.filters = new ArrayList<IFilter>();this.subStr = subStr;}// 继续将 IFilter 接口中的 match() 声明为 abstract,// 由具体的过滤器子类进行实现public abstract boolean match(String word);// 添加过滤器链public void addFilters(ArrayList<CompositeFilter> filters) {this.filters.addAll(filters);}// 添加一个过滤器public void addFilter(IFilter filter) {this.filters.add(filter);}public ArrayList<IFilter> getNextFilter() {return this.filters;}
}
// 过滤单词中包含有某个字符子串的组合型过滤器
class ContainsFilter extends CompositeFilter {public ContainsFilter(String subStr) {super(subStr);}@Overridepublic boolean match(String word) {if (word.contains(super.subStr)) {return true;}return false;}
}
// 过滤单词中以某个字符字串结束的组合型过滤器
class EndFilter extends CompositeFilter {public EndFilter(String subStr) {super(subStr);}@Overridepublic boolean match(String word) {if (word.endsWith(super.subStr)) {return true;}return false;}
}
// 管道
class Pipe {// 字典,相当于流入管道的数据流private Dictionary dictionary;// 用于保存过滤后的最终数据private LinkedHashSet<String> theWords;// 单词查询中需要用到的过滤器树private CompositeFilter filterTree;// 用于保存字典中的所有单词,即数据流中的一个个数据private ArrayList<String> allWords;public Pipe(Dictionary dictionary, CompositeFilter filterTree) {this.dictionary = dictionary;this.filterTree = filterTree;this.theWords = new LinkedHashSet<String>();}public LinkedHashSet<String> getWords() {// 先搜索过滤字典中所有单词,再返回符合要求的单词集合     this.allWords = dictionary.getAllWords();this.findWords();return this.theWords;}private void findWords() {// 对每个单词进行过滤for (String word : allWords) {           if(doFilter(word, filterTree) == true) {this.theWords.add(word);}}}// 递归遍历过滤器树private boolean doFilter(String word, CompositeFilter filterTree) {ArrayList<IFilter> filters = filterTree.getNextFilter();// 标志位,若为 true 则说明该单词符合条件boolean flag = true;for (IFilter filter : filters) {                     if(!filter.match(word)) {flag = false;break;}          // 若是组合型过滤器,即树枝,则递归过滤if (filter instanceof CompositeFilter) {CompositeFilter thisFilter = (CompositeFilter) filter;doFilter(word, thisFilter);}}     return flag;        }
}
// 测试类
public class Client {public static void main(String[] args) {// 创建过滤器: 包含"a"、"b"、"cd"子串,以"end"结尾,长度 > 7// 包含"a"、"b"、"cd"子串的过滤器CompositeFilter filter01 = new ContainsFilter("a");CompositeFilter filter02 = new ContainsFilter("b");CompositeFilter filter03 = new ContainsFilter("cd");// 以"end"结尾的过滤器CompositeFilter endFilter = new EndFilter("end");// 长度 > 7 的过滤器IFilter lengthFilter = new LengthFilter();// 构建过滤器树filter01.addFilter(filter02);filter01.addFilter(filter03);filter01.addFilter(endFilter);filter01.addFilter(lengthFilter);// 自定义一本字典里的所有单词ArrayList<String> allWords = new ArrayList<String>();allWords.add("akkkk");allWords.add("abkkbkcdend");allWords.add("abckk");allWords.add("abdcend");    //长度为6,不符合allWords.add("kakbkck");allWords.add("kkkkkk");allWords.add("bbcc");// 自定义一本字典Dictionary dictionary = new Dictionary(allWords);// 将字典、过滤器树传入管道Pipe pipe = new Pipe(dictionary, filter01);// 单词流在通过管道时被过滤,获取最终单词System.out.println(pipe.getWords());}
}

测试结果:

[abkkbkcdend]

呼…代码太长了,总算是写出来了,从字典中过滤出我们需要的单词了。但是,面对这样的结构,我有如下疑问:

1、上面在 Client 类中并没有“真正”使用到组合模式,它不是一棵过滤器充其量也只是作为一条过滤器而已,没有体现出组合模式那种“层次”,即一个中间过滤器下面还一棵树,在 Client 类中构建过滤器树时其实是一个根节点 filter01 下面链接着其他4个过滤器对象;所以,在代码中的 Pipe 类中进行递归过滤时用得并不实际;

2、我在想,管道过滤器模式中是不是一定要用到组合模式来体现出具有层次之别的过滤器族?如果不是的话,那么用职责链模式来实现我上面的效果我认为会更加便利、快速(接下来我会尝试实现一下),因为在这里体现不出 组合模式(Composite)强调的“整体-部分”的特性(也很有可能是我理解不到位);

3、其实,上面实现的过滤 String 变量可以直接用正则表达式实现,那样子更更更简单,由此不免感叹一下:正则表达式太强大了

转载于:https://blog.51cto.com/haolloyin/348277

管道过滤器模式(Pipe and Filter)与组合模式(修改)相关推荐

  1. 组合模式_设计模式结构性:组合模式(CompositePattern)

    组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象.组合模式依据树形结构来组合对象,用来表示部分以及整体层次.这种类型的设计模式属于结构型模式, ...

  2. php 组合模式,php设计模式(十三)透明组合模式

    组合模式用来解决整体和部分可以一致对待的问题: 比如说 文件夹 和其下的 文件: 可以复制文件也可以复制整个文件夹: 组合模式是将对象组合成树形结构以表示整体和部分的层次结构: 可以方便的增加节点: ...

  3. 设计模式(三):模板方法模式、迭代器和组合模式、状态模式

    八.模板方法模式 1.概念 模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤. 模板就是一个方法,更具体地说 ...

  4. javascript设计模式-组合模式

    1 <!DOCTYPE HTML> 2 <html lang="en-US"> 3 <head> 4 <meta charset=&quo ...

  5. 组合模式(Composite Pattern)

    组合模式概述 定义:组合多个对象形成树形结构以表示具有部分-整体关系的层次结构.组合模式让客户端可以统一对待单个对象和组合对象.又被成为"部分-整体"(Part-Whole)模式, ...

  6. 说说设计模式~组合模式(Composite)

    返回目录 何时能用到它? 组合模式又叫部分-整体模式,在树型结构中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦.对于今天这个 ...

  7. 设计模式 — 结构型模式 — 组合模式

    目录 文章目录 目录 组合模式 应用场景 代码示例 组合模式 组合,将多个对象组合成为一个树状结构,来表示业务逻辑上的层次.组合模式使得用户对单个对象和组合对象的使用具有一致性. 比如,描述一家公司的 ...

  8. 【设计模式】组合模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )

    文章目录 一.组合模式简介 二.组合模式适用场景 三.组合模式优缺点 四.组合模式和访问者模式 五.组合模式代码示例 1.书籍和目录的抽象父类 2.书籍类 3.目录类 4.测试类 一.组合模式简介 组 ...

  9. 组合模式——透明组合模式,安全组合模式

    组合模式 概述 叶子节点进行相关的操作. 可以将这颗树理解成一个大的容器,容器里面包含很多的成员对象,这些成员对象即可是容器对象也可以是叶子对象. 但是由于容器对象和叶子对象在功能上面的区别,使得我们 ...

  10. Java 设计模式之组合模式

    一.了解组合模式 1.1 什么是组合模式 组合模式允许你将对象组合成树形结构来表现"整体/部分"层次机构.组合能够使客户以一致的方式处理个别对象以及组合对象. 组合模式让我们能够用 ...

最新文章

  1. 学习IOS开问题篇--视图的模型控件属性写在私有分类中的原因
  2. Codevs 3134 Circle
  3. 总结CSS3新特性(选择器篇)
  4. 批量杀死MySQL连接的几种方法
  5. cocos2dx 圆盘抽奖_【cocos2dx 3.3 lua】06 抽奖转盘效果
  6. 计算机拆装与网络配置技能,计算机硬件及网络计算机原理与拆装.ppt
  7. python - 接口自动化测试 - MysqlUtil - 数据库操作封装
  8. 2016年零售业CIO的七大革命性挑战
  9. Python中如何安装pip,xlrd
  10. Java实现端口扫描器
  11. 周董演唱会为什么总是抢不到票?教你用Python做一个自动抢票脚本
  12. css文字不换行显示、超出显示点点点等实用性小记
  13. My Sixth-Third Page - 爬楼梯 - By Nicolas
  14. 专访Riverbed CEO:私有化和出售业务瘦身后的Riverbed更专注
  15. windows10安装MySQL8.0
  16. 笔记 :归纳总结 (一)
  17. 时隔一年,我又来捣鼓我家移动光猫了,你还不知道如何获取公网ip吗?
  18. java计算机毕业设计基于安卓Android微信小程序的共享单车租赁系统uniApp
  19. java爬虫工具xpath提取_爬虫 xpath (数据提取)
  20. 【Python数据挖掘】用朴素贝叶斯预测人类活动识别

热门文章

  1. 计算机网络第六版——第二章复习+课后答案
  2. 6-ML的可行性(3)
  3. 科技写作:传递信息要先旧后新
  4. Hibernate的主键生成器generator(zhuan)
  5. 常用的stsadm命令行参数
  6. php mysql可以跨站_PHP防跨站之open_basedir目录设置
  7. bigdicmal除法精度设置_Java BigDecimal浮点数运算--如何保证运算精度不溢出
  8. 安卓应用如何引用动态库
  9. C++对象模型4——多重继承的对象内存模型、vptr与vtbl的创建与重置的时机、不要在含有虚函数的类的构造函数中调用memset
  10. CentOS 8中安装Docker出现和Podman冲突