访问者模式

今天在使用dom4j进行xml解析的时候使用到了访问者模式。

它的使用是这样的,由于dom4j的Node接口中定义了一个accept(Visitor visitor)方法,而Node虚类是dom4j中所有的节点的父类,就相当于Object类一样,但是我们对于xml中的节点的访问应该是不一样的,对于属性,我们应当访问属性名和属性值,对于元素我们应当访问元素值和元素名,对于处理指令我们又要使用不一样的方法访问,他们的调用方法不尽相同。

 

为了方便,我们定义了一个访问者接口:Visitor接口;

Visitor接口提供了这样一些方法:

void visit(Document document);
void visit(DocumentType documentType);
void visit(Element node);
void visit(Attribute node);
void visit(CDATA node);
void visit(Comment node);

………………

 可以看到它基本上把所有的元素都考虑到了,就是说它为每一种元素都提供了一种访问方式。

具体实现的算法却是在具体的类中完成的。

 

下面我们来具体说说什么叫做访问者模式

假设有这样一种情况:现在有个外国军官要来访问中国,他想要看中国的武器,当然了中国为了澄清"中国威胁论",当然要给他看了,有两种武器得给他看啊,第一个是核弹头。第二个就当是J20吧。那么怎么给他看呢?他们都属于武器范畴,但是不一样的东西啊。并且不能把核心机密给泄密了呀?那怎么办呢?访问者模式可以帮得上忙了。

 

给每个武器都添加一个可以接受访问的方法accept(这个当然是要放在超类中的),然后具体如何访问则要在访问者中定义了。好吧!请看代码

package com.gengu.访问者模式;

import java.util.Date;

/**
 * 武器类
 * 描述武器的相关信息
 * */
public abstract class Weapon {

	//型号
	private  String name;
	//用途
	private  String UsdFor;
	//出厂日期
	private  Date date;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getUsdFor() {
		return UsdFor;
	}
	public void setUsdFor(String usdFor) {
		UsdFor = usdFor;
	}
	public Date getDate() {
		return date;
	}
	public void setDate(Date date) {
		this.date = date;
	}
	public abstract void accept(Visitor visitor);
}

 两种武器

package com.gengu.访问者模式;
/**
 * J20战斗机
 * */
public class J20 extends Weapon{

	//性能
	private String performance;

	public String getPerformance() {
		return performance;
	}

	public void setPerformance(String performance) {
		this.performance = performance;
	}

	@Override
	public void accept(Visitor visitor) {
		visitor.visit(this);
	}
	
}

package com.gengu.访问者模式;

/**
 * 这里是核弹
 * */
public class Nbomb extends Weapon{
	//核当量
	private String equivalent;

	public String getEquivalent() {
		return equivalent;
	}
	public void setEquivalent(String equivalent) {
		this.equivalent = equivalent;
	}
	@Override
	public void accept(Visitor visitor) {
		visitor.visit(this);
	}
}
  

 然后就是访问者了

package com.gengu.访问者模式;

/**
 * 访问接口
 * */
public interface Visitor {

	/**我可以访问弹头*/
	public void visit(Nbomb nbomb);
	/**还可以访问J-20*/
	public void visit(J20 j20);
	
}

 访问者类的具体接口

package com.gengu.访问者模式;

public class VisitorImpl implements Visitor{
	public void visit(){}

	@Override
	public void visit(Nbomb nbomb) {
		StringBuffer stringBuffer = new StringBuffer();
		stringBuffer.append("武器的名字:"+nbomb.getName()+"\n");
		stringBuffer.append("出厂日期:"+nbomb.getDate()+"\n");
		stringBuffer.append("战略用途:"+nbomb.getUsdFor()+"\n");
		stringBuffer.append("武器的核当量:"+nbomb.getEquivalent());
		System.out.println(stringBuffer.toString());
		
	}

	@Override
	public void visit(J20 j20) {
		StringBuffer stringBuffer = new StringBuffer();
		stringBuffer.append("武器的名字:"+j20.getName()+"\n");
		stringBuffer.append("出厂日期:"+j20.getDate()+"\n");
		stringBuffer.append("战略用途:"+j20.getUsdFor()+"\n");
		stringBuffer.append("武器的核当量:"+j20.getPerformance());
		System.out.println(stringBuffer.toString());
	}

}

 下面是场景类

package com.gengu.访问者模式;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class Client {

	public static void main(String[] args) {
		for(Weapon weapon:makeWeapon()){
			weapon.accept(new VisitorImpl());
			System.out.println("================");
		}
		
	}
	public static List<Weapon> makeWeapon(){
		
		List<Weapon> weapons = new ArrayList<Weapon>();
		Nbomb nbomb = new Nbomb();
		nbomb.setDate(new Date());
		nbomb.setEquivalent("4000W");
		nbomb.setName("核弹头");
		nbomb.setUsdFor("威慑");
		weapons.add(nbomb);
		
		J20 j20 = new J20();
		j20.setDate(new Date());
		j20.setName("歼20");
		j20.setPerformance("性能优越");
		j20.setUsdFor("战略打击");
		weapons.add(j20);
		
		return weapons;
	}
	
}

 这样我们就达到了对于核弹头和飞机的不同的处理,访问非常简单。屏蔽了底层的处理。客户端根本不用理会底层是怎么样让他访问的,只需要按照访问者的规则去得到访问结果就可以了。

 

优点:符合单一职责原则,具有优秀的扩展性,灵活性非常高。

 

你可能感兴趣的:(访问者模式)