管道过滤器模式(Pipe and Filter)与组合模式(修改)
转自:http://haolloyin.blog.51cto.com/1177454/348277
之前在 benjielin 前辈的博客中看到“管道过滤器(Pipe-And-Filter)模式(http://bj007.blog.51cto.com/1701577/345677)”,当时将文章中运用到的组合模式(Composite)与我刚刚写过的装饰模式(Decorator)和职责链模式(Chain of Responsibility)混为一谈,并希望用这后面两个模式进行代码实现,+_+
现在觉得还是先把那文章中的组合模式给具体实现一下吧,具体的文字描述请看上面文章链接哦。
在我的代码中,我假设的需求是:给定多个条件(即过滤器),遍历一本字典中的所有单词,将同时符合所有条件的所有单词查询(过滤)出来。现假定需要过滤出“单词中同时包含a、b、cd字串,并且以"end”结尾,最后是单词的长度大于7 ”。
好了,看清了需求,得出类图如下:
- // 字典
- class Dictionary {
- // 字典里面有好多单词
- private ArrayList<String> allWords;
- public Dictionary(ArrayList<String> allWords) {
- this.allWords = allWords;
- }
- // 获取字典中所有单词
- public ArrayList<String> getAllWords() {
- return this.allWords;
- }
- }
- // 过滤器接口,只有 match() 方法
- interface IFilter {
- public boolean match(String word);
- }
- // 树叶型过滤器,过滤单词中长度大于指定长度
- class LengthFilter implements IFilter {
- private int length;
- public LengthFilter(int length) {
- this.length = length;
- }
- @Override
- public boolean match(String word) {
- if (word.length() > length) {
- return true;
- }
- return false;
- }
- }
- // 树叶型过滤器,过滤单词中包含有某个字符字串
- class ContainsFilter implements IFilter {
- private String subStr;
- public ContainsFilter(String subStr) {
- this.subStr = subStr;
- }
- @Override
- public boolean match(String word) {
- if (word.contains(subStr)) {
- return true;
- }
- return false;
- }
- }
- // 树叶型过滤器,过滤单词中以某个字符字串结束
- class EndFilter implements IFilter {
- private String subStr;
- public EndFilter(String subStr) {
- this.subStr = subStr;
- }
- @Override
- public boolean match(String word) {
- if (word.endsWith(subStr)) {
- return true;
- }
- return false;
- }
- }
- // 抽象组合型过滤器,类似于树枝节点
- abstract class CompositeFilter implements IFilter {
- protected ArrayList<IFilter> filters;
- public CompositeFilter() {
- this.filters = new ArrayList<IFilter>();
- }
- // 继续将 IFilter 接口中的 match() 声明为 abstract,
- // 由具体的过滤器子类进行实现
- public abstract boolean match(String word);
- // 添加过滤器链
- public void addFilters(ArrayList<IFilter> filters) {
- this.filters.addAll(filters);
- }
- // 添加一个过滤器
- public void addFilter(IFilter filter) {
- this.filters.add(filter);
- }
- // 既然是树枝过滤器,其下必有子过滤器
- public ArrayList<IFilter> getFilters() {
- return this.filters;
- }
- }
- // and 过滤器,树枝型过滤器
- class AndFilter extends CompositeFilter {
- @Override
- public boolean match(String word) {
- for(IFilter filter : super.filters) {
- if(!(filter.match(word))) {
- return false;
- }
- }
- return true;
- }
- }
- // or 过滤器,树枝型过滤器
- class OrFilter extends CompositeFilter {
- @Override
- public boolean match(String word) {
- for(IFilter filter : super.filters) {
- if(filter.match(word)) {
- return true;
- }
- }
- return false;
- }
- }
- // 管道
- class Pipe {
- // 字典,相当于流入管道的数据流
- private Dictionary dictionary;
- // 用于保存过滤后的最终数据
- private LinkedHashSet<String> theWords;
- // 单词查询中需要用到的过滤器树
- private IFilter filterTree;
- // 用于保存字典中的所有单词,即数据流中的一个个数据
- private ArrayList<String> allWords;
- public Pipe(Dictionary dictionary, IFilter 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(filterTree.match(word) == true) {
- this.theWords.add(word);
- }
- }
- }
- }
- // 测试类
- public class Client {
- public static void main(String[] args) {
- // 创建过滤器树: 包含"a"、"b"、"cd"子串,以"end"结尾,长度 > 7
- // 同时包含"a"、"b"、"cd"子串的过滤器
- CompositeFilter andFilter = new AndFilter();
- IFilter contain01 = new ContainsFilter("a");
- IFilter contain02 = new ContainsFilter("b");
- IFilter contain03 = new ContainsFilter("cd");
- andFilter.addFilter(contain01);
- andFilter.addFilter(contain02);
- andFilter.addFilter(contain03);
- // 以 "end" 或 "END" 结尾的过滤器
- CompositeFilter orFilter = new OrFilter();
- IFilter end01 = new EndFilter("end");
- IFilter end02 = new EndFilter("END");
- orFilter.addFilter(end01);
- orFilter.addFilter(end02);
- // 长度 > 7 的过滤器
- IFilter lengthFilter = new LengthFilter(7);
- // 构建过滤器树,用根过滤器将上面的所有过滤器组合起来
- CompositeFilter rootFilter = new AndFilter();
- rootFilter.addFilter(andFilter);
- rootFilter.addFilter(orFilter);
- rootFilter.addFilter(lengthFilter);
- // 自定义一本字典里的所有单词
- ArrayList<String> allWords = new ArrayList<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");
- // 自定义一本字典
- Dictionary dictionary = new Dictionary(allWords);
- // 将字典、过滤器树传入管道
- Pipe pipe = new Pipe(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 of Responsibility)的Java实现http://haolloyin.blog.51cto.com/1177454/342166
以下是修改前的部分内容,可不看,因为太不合理了。但我还是想保存着,毕竟是从以下代码修改而来的,所以可以参看benjielin前辈的评论来看。
类图如下:
代码如下:
//树叶型过滤器,直接实现 IFilter ,过滤单词中长度大于 7
class LengthFilter implements IFilter {
@Override
public 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);
} @Override
public boolean match(String word) {
if (word.contains(super.subStr)) {
return true;
}
return false;
}
}
// 过滤单词中以某个字符字串结束的组合型过滤器
class EndFilter extends CompositeFilter { public EndFilter(String subStr) {
super(subStr);
} @Override
public 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 变量可以直接用正则表达式实现,那样子更更更简单,由此不免感叹一下:正则表达式太强大了;
管道过滤器模式(Pipe and Filter)与组合模式(修改)的更多相关文章
- 设计模式(十)组合模式(Composite Pattern)
一.引言 在软件开发过程中,我们经常会遇到处理简单对象和复合对象的情况,例如对操作系统中目录的处理就是这样的一个例子,因为目录可以包括单独的文件,也可以包括文件夹,文件夹又是由文件组成的,由于简单对象 ...
- c#设计模式-组合模式
在软件开发过程中,我们经常会遇到处理简单对象和复合对象的情况,例如对操作系统中目录的处理就是这样的一个例子,因为目录可以包括单独的文件,也可以包括文件夹,文件夹又是由文件组成的,由于简单对象和复合对象 ...
- C#设计模式系列:组合模式(Composite)
1.组合模式简介 1.1>.定义 组合模式主要用来处理一类具有“容器特征”的对象——即它们在充当对象的同时,又可以作为容器包含其他多个对象. 1.2>.使用频率 中高 2.组合模式结构图 ...
- 说说设计模式~组合模式(Composite)
返回目录 何时能用到它? 组合模式又叫部分-整体模式,在树型结构中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦.对于今天这个 ...
- 设计模式学习之组合模式(Composite,结构型模式)(10)
转载地址:http://www.cnblogs.com/zhili/p/CompositePattern.html 一.引言 在软件开发过程中,我们经常会遇到处理简单对象和复合对象的情况,例如对操作系 ...
- 组合模式(Composite Pattern)
组合模式主要用来处理一类具有“容器特征”的对象——即它们在充当对象的同时,又可以作为容器包含其他多个对象. 组合模式实现的最关键的地方是——简单对象和复合对象必须实现相同的接口.这就是组合模式能够将组 ...
- C#设计模式(10)——组合模式(Composite Pattern)
一.引言 在软件开发过程中,我们经常会遇到处理简单对象和复合对象的情况,例如对操作系统中目录的处理就是这样的一个例子,因为目录可以包括单独的文件,也可以包括文件夹,文件夹又是由文件组成的,由于简单对象 ...
- javascript设计模式学习之十——组合模式
一.组合模式定义及使用场景 组合模式将对象组合成树形结构,用以表示“部分—整体”的层次结构,除了用来表示树形结构之外,组合模式还可以利用对象的多态性表现,使得用户对单个对象和组合对象的使用具有一致性. ...
- C#设计模式之十组合模式(Composite)【结构型】
一.引言 今天我们要讲[结构型]设计模式的第四个模式,该模式是[组合模式],英文名称是:Composite Pattern.当我们谈到这个模式的时候,有一个物件和这个模式很像,也符合这个模式要表达 ...
- PHP设计模式之组合模式
当我们的一个对象可能代表一个单一的实体,或者一个组合的实体,但是仍然需要通过同样的方式被使用时,这种情形则适合使用组合模式的设计. 组合模式是一种结构型模式. 当看了书上的解释之后,并不是很理解,遂去 ...
随机推荐
- Centos 7防火墙firewalld开放80端口(转)
开启80端口 firewall-cmd --zone=public --add-port=80/tcp --permanent 出现success表明添加成功 命令含义: --zone #作用域 -- ...
- Nginx 开启gzip 压缩
随着nginx的发展,越来越多的网站使用nginx,因此nginx的优化变得越来越重要,今天我们来看看nginx的gzip压缩到底是怎么压缩的呢? gzip(GNU-ZIP)是一种压缩技术. 经过gz ...
- 登录phpmyadmin提示: #1045 无法登录 MySQL 服务器
打开phpmyadmin,进行登录,出现以下问题,提示:#1045 无法登录 MySQL 服务器 或许出现以下错误情况:phpmyadmin:#1045 无法登录 MySQL 服务器.Access d ...
- 给button按钮加回车事件
<button class="login-btn" id="login">立即登录</button> $("body" ...
- js 实现进度条功能。
/** * 纯js进度条 * Created by kiner on 15/3/22. */ function progress(options){ this.w = (options &&a ...
- python3 如何使用ip、爬虫
使用urllib.request.random模块,不说了贴代码 url="*"; iplist=['70.254.226.206:8080'];proxy_support=url ...
- 2016年中国大学生程序设计竞赛(合肥)-重现赛1008 HDU 5968
异或密码 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submis ...
- 开启Java博客
已经转Java大半年了,Java知识都来自于工作,没有一个系统的学习,所以这一个多月我都在看Java的一些基本东西,准备系统性的学习下Java知识.这一个多月看的也挺多,从servlet,jsp,st ...
- 创建Maven web项目时 出现 web.xml is missing and <failOnMissingWebXml> is set to true错误 pox.xml编译错误
今天创建一个maven项目 pom.xml出现如下错误: web.xml is missing and <failOnMissingWebXml> is set to true 这是因为你 ...
- markdown 语法测试
understanding the linux kernel 绪论 linux支持.硬件依赖.版本 基于微内核的方法 支持内核线程 多线程应用支持 抢占式内核 硬件依耐性 file descripto ...