求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
 
Visitor Parttern
 

2011-06-02 来源:网络

 

模式背景: 今天在看<<java 并发编程 设计原则与模式>>中, 涉及到了Visitor模式. 在并发过程中, 当一个类中持有一个集合的时候, 如果需要遍历这个集合,

就不能单纯的考虑把整个集合返回给调用方.因为这样就给调用方提供了改变集合的操作. 试想,当你花费了大量的synchronized方法或者使用了多

么高明的lock-free算法进行性能上的优化,一旦你向外界返回了你要保护的对象,一切都将是一场"灾难". 矛盾的是, 你无法预测客户会使用什么样的方式来进行对你集合中的元素进行操作. 困难如下:

private List<T> yourList; .....

public synchronized void doIterator(){

for(T t: yourList){
<how to do with element e ...??>

}
}

你如何确认对方需要做的操作时什么呢? 答案是没有. 基于面对对象的操作. 遍历的方式不变, 如果是串行的数据结构,无非就是循环. 如果是树状结构那么可能会不一样的遍历方式. 就如同蛋糕店中一样,他们给你返回了蛋糕,可是要怎么去吃,那是你自己的事情. 想到这点, 就应该清楚一件事情, 调用方的操作理应"自己知道".那么就变成了如下的形式:

private List<T> yourList;

.....

public void doIterator(Client : client){

for(T t: yourList){

client.doWithElemnt(t);

}

}

看到这里, 也许还有问题: 我怎么知道你是使用"doWithElemnt(..)"这个方式去消费呢? 换句话说,这是一种约定,java中,标准时用Interface来表示. 这样就形成了这样的一个"调用方"的结构:

当有client来遍历的时候,就调用它的visit方法,并把蛋糕给他. 事情就是这么简单!

客户的问题解决了,但是客户真正想要的是蛋糕,并不是整个"蛋糕池". 理解这一点很重要, 因为它进一步确定了我们不应该在doIterator方法中调用客户端.

而是应该在List<T>的每一个t上调用,代码进一步更改:

private List<T> yourList; .....

public void doIterator(){

for(T t: yourList){

t.accept(visitor);

}

}

...

T 中的accept方法如下:

visitor.visit(this);

如此一来, doIterator方法拜托了visitor的依赖. 那么,在doIterator方法中,有怎么样知道就是需要调用t.accept()方法呢? 一样地,

Interface的标准化.

这么一来,就形成了visitor模式:

结束语: 可以使用java Reflection的反射机制使得Viditor模式更加具有灵活性.



如何向妻子解释OOD
OOAD与UML笔记
UML类图与类的关系详解
UML统一建模语言初学
总结一下领域模型的验证
基于 UML 的业务建模


面向对象的分析设计
基于UML的面向对象分析设计
UML + 嵌入式系统分析设计
关系数据库面向OOAD设计
业务建模与业务架构
使用用例进行需求管理


某航空IT部门 业务分析与业务建模
联想 业务需求分析与建模
北京航管科技 EA工具与架构设计
使用EA和UML进行嵌入式系统分析
全球最大的茶业集团 UML系统分析
华为 基于EA的嵌入式系统建模
水资源服务商 基于EA进行UML建模
更多...