管道过滤器模式(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 ”。

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

  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 {
	@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 变量可以直接用正则表达式实现,那样子更更更简单,由此不免感叹一下:正则表达式太强大了

时间: 2024-10-25 10:02:26

管道过滤器模式(Pipe and Filter)与组合模式(修改)的相关文章

模式解密(13)- 组合模式

1.简介 定义:允许你将对象组合成树形结构来表现"整体-部分"层次结构. 组合能让客户以一致的方法处理个别对象以及组合对象. 主要解决:它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦. 英文:Composite 类型:结构型 2.类图及组成 (引)类图: 组成: ● Component(抽象构件):接口或抽象类,为叶子构件和容器构件对象声明接口,在该角色中可以包含所有子类共有行为的缺省声明

10.设计模式_组合模式

转载自   http://www.cnblogs.com/zhili/p/CompositePattern.html 一.引言 在软件开发过程中,我们经常会遇到处理简单对象和复合对象的情况,例如对操作系统中目录的处理就是这样的一个例子,因为目录可以包括单独的文件,也可以包括文件夹,文件夹又是由文件组成的,由于简单对象和复合对象在功能上区别,导致在操作过程中必须区分简单对象和复合对象,这样就会导致客户调用带来不必要的麻烦,然而作为客户,它们希望能够始终一致地对待简单对象和复合对象.然而组合模式就是

设计模式 -- 组合模式(Composite)

写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------主要内容包括: 初识组合模式,包括:定义.结构.参考实现 体会组合模式,包括:场景问题.不用模式的解决方案.使用模式的解决方案 理解组合模式,包括:认识组合模式.安全性和透明性.父组件引用.环状引用.组合模式的优缺点 思考组合模式,包括:组合模式的本质.何时选用 参考内容: 1.<研磨设计模式> 一书,作者:陈臣.王斌 --

php中的组合模式

刚看完了<深入php面向对象.模式与实践>一书中组合模式这块内容,为了加深理解和记忆,所以着手写了这篇博客. 为方便后续理解,此处先引入两个概念,局部对象和组合对象. 局部对象:无法将其他对象组合到自身内部属性上的对象.即不能组合其他对象的对象. 组合对象:可以将其他对象组合到自身内部属性上的对象.即可以组合其他对象的对象. 注:将对象A的某个属性中存储着对象B对象的引用,则表示A与B有组合关系,其中A将B组合到了自身内部. 首先我们通过给出下面的业务需求,来引入组合模式: 业务部门想要开发一

javascript设计模式学习之十——组合模式

一.组合模式定义及使用场景 组合模式将对象组合成树形结构,用以表示“部分—整体”的层次结构,除了用来表示树形结构之外,组合模式还可以利用对象的多态性表现,使得用户对单个对象和组合对象的使用具有一致性. 实现组合模式的关键: 在java等静态语言中,需要单个对象和组合对象都实现同样的抽象接口,这可以通过抽象类或者接口来实现. 在javascript中,对象的多态性是与生俱来的,没有编译器去检查对象的类型,因此实现组合模式的要点是保证组合兑现个单个对象用友同样的方法,这通常需要使用“鸭子类型”的思想

组合模式(Composite Pattern)

转:http://www.cnblogs.com/doubleliang/archive/2011/12/27/2304104.html 简而言之,就是让所有的叶子节点执行相同的操作!!!!!!!!!!!!!!! 组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性. 有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构

组合模式之拼凑的美好

廊坊的风一如既往的在窗外刮着,天地间肆意地飘洒,纵情在一刹那,为何如今仅仅剩下风吹乱我的发,乱蓬蓬的,还是去超市逛逛吧,买吃的`(*∩_∩*)′,走进华联超市,热情的店员招呼着我,開始为我介绍,推荐各种各样商品,店员向我推荐了他们的会员卡,全场全部项目均八折,每逢节假日打五折,我心想那太划算了,并且他们总店,分店,加盟店都能够用,所以就办了张会员卡.今天我们的设计模式就从超市会员卡開始说起. 这个俨然就是我们设计模式中的组合模式----组合模式有时候又叫做部分-总体模式,它使我们树型结构的问题中

设计模式之八:组合模式(Composite Pattern)

什么是组合模式呢?简单来说组合模式就是将对象合成树形结构以表示"部分整体"的层次结构,组合模式使用户对单个对象和组合对象使用具有一致性. 组合模式(Composite Pattern)有时候又叫部分-整体模式,它使我们在树型结构的问题中,模糊了简单元素和负责元素的概念,客户程序可以向处理简单元素一样处理负责元素,从而使得客户程序与复杂元素的的内部结构解耦. 组合模式让你可以优化处理递归或分级数据结构.关于分级数据结构的一个经典例子就是电脑中的文件系统.文件系统由目录和文件组成,所有目录

PHP设计模式之组合模式

当我们的一个对象可能代表一个单一的实体,或者一个组合的实体,但是仍然需要通过同样的方式被使用时,这种情形则适合使用组合模式的设计. 组合模式是一种结构型模式. 当看了书上的解释之后,并不是很理解,遂去翻了翻<大化设计模式>,以下为原文截图: 看完这本书上的解释之后也不是很理解,但是能够进行编码了,以下为组合模式的代码: <?php /** * 组合模式抽象基类 */ abstract class CompanyBase{ //节点名称 protected $name; public fu

《javascript设计模式》笔记之第九章:组合模式

之前一直都是按照书的结构顺序做总结,觉得好像不是很好,现在试着完全按照自己的理解做总结.例子还是书上的例子. 一:组合模式的作用: 在web开发中,主要用于创建嵌套的html结点,使得我们方便的把各种结点连接起来,并且提供简易的操作.   二:组合模式的结构: 结构就像我们的文件结构一样讲Composite理解为文件夹,Leaf理解为文件就好理解了.   三:例子一,创建一个组合的表单 需求:试想着我们想要构建一个表单,但是表单域经常要被产品经理修改,我们怎样才能利用js快速的搭建这个form呢