[TOC]

模式定义

访问者模式:表示一个作用于某对象结构中的各元素的操作,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。所以访问者模式是一种对象行为型模式。

模式角色

访问者模式包括如下角色:

  • Vistor(抽象访问者)
  • ConcreteVisitor(具体访问者)
  • Element(抽象元素)
  • ConcreteElement(具体元素)
  • ObjectStructure(对象结构)

模式分析

访问者模式的对象结构存储了不同类型的元素对象,以供不同的访问者访问

访问者模式包括了两个层次结构,一个是访问者层次结构,提供了抽象访问者和具体访问者,一个是元素层级结构,提供了抽象元素和具体元素

相同的访问者可以以不同的方式访问不同的元素,相同的元素可以接受不同的访问者以不同访问方式访问。

典型代码:

抽象访问者类

public abstract class Visitor
{
public abstract void visit(ConcreteElementA elementA);
public abstract void visit(ConcreteElementB elementB);
public void visit(ConcreteElementC elementC)
{
//元素ConcreteElementC操作代码
}
}

具体访问者类

public class ConcreteVisitor extends Visitor
{
public void visit(ConcreteElementA elementA)
{
//元素ConcreteElementA操作代码
}
public void visit(ConcreteElementB elementB)
{
//元素ConcreteElementB操作代码
}
}

抽象元素类

public interface Element
{
public void accept(Visitor visitor);
}

具体元素类

public class ConcreteElementA implements Element
{
public void accept(Visitor visitor)
{
visitor.visit(this);
}

public void operationA()
{
//业务方法
}
}

对象结构类

public class ObjectStructure
{
private ArrayList list=new ArrayList();
public void accept(Visitor visitor)
{
Iterator i=list.iterator();

while(i.hasNext())
{
((Element)i.next()).accept(visitor);
}
}
public void addElement(Element element)
{
list.add(element);
}
public void removeElement(Element element)
{
list.remove(element);
}
}

模式例子

本例子来自​《设计模式》​一书



实例一:购物车
顾客在超市中将选择的商品,如苹果、图书等放在购物车中,然后到收银员处付款。在购物过程中,顾客需要对这些商品进行访问,以便确认这些商品的质量,之后收银员计算价格时也需要访问购物车内顾客所选择的商品。此时,购物车作为一个ObjectStructure(对象结构)用于存储各种类型的商品,而顾客和收银员作为访问这些商品的访问者,他们需要对商品进行检查和计价。不同类型的商品其访问形式也可能不同,如苹果需要过秤之后再计价,而图书不需要。使用访问者模式来设计该购物过程。


抽象的访问者类

public abstract class Visitor
{
protected String name;

public void setName(String name)
{
this.name=name;
}

public abstract void visit(Apple apple);

public abstract void visit(Book book);
}

具体的访问者类:

public class Saler extends Visitor
{
public void visit(Apple apple)
{
System.out.println("收银员" + name + "给苹果过秤,然后计算其价格。");
}

public void visit(Book book)
{
System.out.println("收银员" + name + "直接计算书的价格。");
}
}
public class Customer extends Visitor
{
public void visit(Apple apple)
{
System.out.println("顾客" + name + "选苹果。");
}

public void visit(Book book)
{
System.out.println("顾客" + name + "买书。");
}
}

元素接口类:

public interface Product
{
void accept(Visitor visitor);
}

具体的元素类:

public class Apple implements Product
{
public void accept(Visitor visitor)
{
visitor.visit(this);
}
}
public class Book implements Product
{
public void accept(Visitor visitor)
{
visitor.visit(this);
}
}

对象结构类:

import java.util.*;

public class BuyBasket
{
private ArrayList list=new ArrayList();

public void accept(Visitor visitor)
{
Iterator i=list.iterator();

while(i.hasNext())
{
((Product)i.next()).accept(visitor);
}
}

public void addProduct(Product product)
{
list.add(product);
}

public void removeProduct(Product product)
{
list.remove(product);
}
}

客户端类:

public class Client
{
public static void main(String a[])
{
Product b1=new Book();
Product b2=new Book();
Product a1=new Apple();
Visitor visitor;

BuyBasket basket=new BuyBasket();
basket.addProduct(b1);
basket.addProduct(b2);
basket.addProduct(a1);

visitor=(Visitor)XMLUtil.getBean();

visitor.setName("张三");

basket.accept(visitor);
}
}
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.io.*;
public class XMLUtil
{
//该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象
public static Object getBean()
{
try
{
//创建文档对象
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File("config.xml"));

//获取包含类名的文本节点
NodeList nl = doc.getElementsByTagName("className");
Node classNode=nl.item(0).getFirstChild();
String cName=classNode.getNodeValue();

//通过类名生成实例对象并将其返回
Class c=Class.forName(cName);
Object obj=c.newInstance();
return obj;
}
catch(Exception e)
{
e.printStackTrace();
return null;
}
}
}

config.xml

<?xml version="1.0"?>
<config>
<className>Saler</className>
</config>

模式应用

  • java xml处理的DOM4j,通过访问者模式的方式来读取并解析XML文档,VisitorSupport是DOM4J提供的Visitor接口的默认适配器

public class MyVisitor extends VisitorSupport 
{
public void visit(Element element)
{
System.out.println(element.getName());
}
public void visit(Attribute attr)
{
System.out.println(attr.getName());
}
},

....