java:23种设计模式之一Visitor模式

JAVA的设计模式经前人总结可以分为23种
设计模式根据使用类型可以分为三种:
1、 创建模式:Factory(工厂模式)、Singleton(单态)、Builder(建造者模式)、Prototype(原型模式)、工厂方法模式。
2、 结构模式:Flyweight(共享模式)、Bridge(桥模式)、Decorator(装饰模式)、Composite(组合模式)、Adapter(适配器模式)、Proxy(代理模式)、Facade (外观模式)。
3、 行为模式:Iterator(迭代模式)、Template(模板模式)、Chain of Responsibility(责任链模式)、Memento(纪念品模式)、Mediator(中介模式)、Interpreter(解释器模式)、Strategy(策略模式)、State 、Observer(观察者模式)、Visitor(访问模式)、Command(命令模式)。
注:以上翻译不甚准确,以英文为准。

一、Visitor模式定义:

作用于某个对象群中各个对象的操作. 它可以使你在不改变这些对象本身的情况下,定义作用于这些对象的新操作.在Java中,Visitor模式实际上是分离了collection结构中的元素和对这些元素进行操作的行为.

二、Visitor模式构成:

Visitor模式由被访问者(Visitable)和访问者(Visitor)构成,两者之间是互动的关系,即双方必须提供接口供彼此访问。下面是Visitor模式的一个例子(参考自www.jdon.com)

·被访问者接口

public   interface  Visitable  {

   
public void accept(Visitor visitor);
}

 


·被访问者接口实现类

 

public   class  StringElement  implements  Visitable  {
   
private String value;

   
public StringElement(String string) {
      value 
= string;
   }


   
public String getValue(){
      
return value;
   }


   
// 定义accept的具体内容 这里是很简单的一句调用
   public void accept(Visitor visitor) {
      visitor.visitString(
this);  // 被访问者接受了一个访问者,把自己作为回调方法中的参数
   }

}


·访问者接口

public   interface  Visitor  {
   
public void visitString(StringElement stringE);
   
public void visitFloat(FloatElement floatE);     
   
public void visitCollection(Collection collection); 
}


注:因为这里被访问对象的类型已经明确,所以方法的形参定义可以具体到接口实现类,而不需要用接口类型


·访问者接口实现类

public   class  ConcreteVisitor  implements  Visitor  {
   
// 在本方法中,我们实现了对Collection的元素的成功访问
   public void visitCollection(Collection collection) {
      Iterator iterator 
= collection.iterator()
      
while (iterator.hasNext()) {
         Object o 
= iterator.next();
         
if (o instanceof Visitable)       
            ((Visitable)o).accept(
this);
      }
 
   }


   
public void visitString(StringElement stringE) {
      System.out.println(
"'"+stringE.getValue()+"'");
   }
 

   
public void visitFloat(FloatElement floatE){
      System.out.println(floatE.getValue().toString()
+"f");
   }
 
}


·客户端调用代码

Visitor visitor  =   new  ConcreteVisitor();

StringElement stringE 
=   new  StringElement( " I am a String " );
visitor.visitString(stringE);

Collection list 
=   new  ArrayList();
list.add(
new  StringElement( " I am a String1 " )); 
list.add(
new  StringElement( " I am a String2 " )); 
list.add(
new  FloatElement( new  Float( 12 ))); 
list.add(
new  StringElement( " I am a String3 " )); 
visitor.visitCollection(list);


作为Visitor模式中的被访问者,通常都需要定义一个setXxx和getXxx方法,为访问者访问时提供接口。或者像上例一样,采用Call-back机制。而访问者也需要提供相应的接口来接收被访问者,以输出其内容。

三、Visitor模式的优缺点

从这个例子就可以看出Visitor模式的一个缺点:对于集合中的所有类型元素,访问者必须穷举所有的可能方法,一旦元素的类型比较多,则访问者的类将显得比较庞大。

StringElement只是一个实现,可以拓展为更多的实现,整个核心奥妙在accept方法中,在遍历Collection时,通过相应的accept方法调用具体类型的被访问者。这一步确定了被访问者类型。

Visitor模式的一个优点体现在对集合元素的访问中:由于集合中的可访问元素都实现了Visitable接口,所以在迭代集合的过程中,我们可以将每个元素都看成是接口类型。
 
其次由于JAVA语言的多态性,虽然每个元素都是接口类型(Visitable),但每个元素的实现类不同,所以在调用accept方法时,虚拟机“知道”应该调起那个正确的方法(例如:集合中的一个String元素,会调用StringElement的accept方法)

Visitor对集合类型的访问过程:对集合进行迭代,将自身作为参数调用每个被访问者的accept方法,被访问者的accept方法也以自身为参数回调访问者的visitXxx方法。

四、Visitor模式的使用前提和注意点

使用访问者模式前提是对象群结构中(Collection) 中的对象类型很少改变。

在两个接口Visitor和Visitable中,确保Visitable很少变化,也就是说,确保不能老有新的Element元素类型加进来,可以变化的是访问者行为或操作,也就是Visitor的不同子类可以有多种,这样使用访问者模式最方便.

如果对象集合中的对象集合经常有变化, 那么不但Visitor实现要变化,Visistable也要增加相应行为,GOF建议是,不如在这些对象类中直接逐个定义操作,无需使用访问者设计模式。

--摘自www.jdon.com的《Visitor模式》 一节

原因:

如果Visitable中元素的类型是固定的或者很少变化的,那么即使Visitor中相应的访问行为发生改变了,对Visitable也没有影响。相反如果Visitable中元素的类型变化频繁,除了Visitable要增加新的类型,Visitor也要增加相应的visitXxx方法。所以说使用Visitor模式的一个前提是被访问者的类型很少改变

 

你可能感兴趣的:(java:23种设计模式之一Visitor模式)