java之访问者模式

本文介绍了访问者模式,其可在不改变数据结构前提下定义新操作。阐述了抽象访问者、具体访问者等角色,给出示例。分析表明,该模式有扩展性好、复用性高、分离无关行为等优点,但存在对象结构变化困难、破坏封装等缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

访问者模式

定义

封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

角色

在这里插入图片描述

  1. 抽象访问者(Visitor)角色:声明了一个或者多个方法操作,形成所有的具体访问者角色必须实现的接口。
  2. 具体访问者(ConcreteVisitor)角色:实现抽象访问者所声明的接口,也就是抽象访问者所声明的各个访问操作。
  3. 抽象节点(Node)角色:声明一个接受操作,接受一个访问者对象作为一个参数。
  4. 具体节点(ConcreteNode)角色:实现了抽象节点所规定的接受操作。
  5. 结构对象(ObjectStructure)角色:有如下的责任,可以遍历结构中的所有元素;如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素;如果需要,可以设计成一个复合对象或者一个聚集,如List或Set。

示例

以两个节点为例,visitor需要两个方法分别访问两个节点

public interface Visitor {
	public void visit(NodeA node);
	public void visit(NodeB node);
}

具体的visitorA访问拿到具体的node对象

public class VisitorA implements Visitor{

	@Override
	public void visit(NodeA node) {
		System.out.println("VisitorA访问:"+node.operationA());
	}

	@Override
	public void visit(NodeB node) {
		System.out.println("VisitorA访问:"+node.operationB());
	}
}

node接口,接受visitor访问

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

具体的节点nodeA,接受访问者访问并返回自身对象

public class NodeA implements Node {

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

	public String operationA(){
		return "NodeA";
	}
}

具体的节点nodeB,接受访问者返回自身对象

public class NodeB implements Node {

	@Override
	public void accept(Visitor visitor) {
		visitor.visit(this);
	}
	
	public String operationB(){
		return "NodeB";
	}
}

拥有节点的聚集对象

public class ObjectStructure {

	private List<Node> nodes;
	
	public ObjectStructure() {
		this.nodes = new ArrayList<Node>();
	}
	
	public void addNode(Node node){
		this.nodes.add(node);
	}
	
	public void deleteNode(Node node){
		this.nodes.remove(node);
	}
	
	public void action(Visitor visitor){
		for (Node node : nodes) {
			node.accept(visitor);
		}
	}
}

测试类

public class VisitorTest {

	public static void main(String[] args) {
		ObjectStructure objectStructure = new ObjectStructure();
		
		objectStructure.addNode(new NodeA());
		objectStructure.addNode(new NodeB());
		
		//提供操作方法让visitor一一访问每个node
		objectStructure.action(new VisitorA());
	}
}

分析

  1. node接口对象accept接受visitor的访问,visitor调用visit方法访问node对象并动态传入具体的node实现类(nodeA,nodeB等),然后对具体的node实现类操作,从而达到不修改原来node集合的数据结构的情况下操作数据,例如这里如果再新增一个节点nodeC,只需要在visitor接口中增加一个对nodeC的访问,然后将nodeC增加到集合中,那么我就可以实现对nodeC的操作;
  2. 假设不用访问者模式,由于集合中存放的是Node接口,往集合中增加接口实现类,之后在想取得具体的实现类是很难实现的,例如上面例子中的objectStructure中存放NodeA跟NodeB对象,从objectStructure取出来全是Node对象不能向下转型成具体的实现类,因此不能针对具体实现类操作,用访问者模式则会动态的访问到子类的重写的方法(其实是实现具体的接口)从而获取到具体的子类实例对象;

优点

  1. 好的扩展性
    能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
  2. 好的复用性
    可以通过访问者来定义整个对象结构通用的功能,从而提高复用程度。
  3. 分离无关行为
    可以通过访问者来分离无关的行为,把相关的行为封装在一起,构成一个访问者,这样每一个访问者的功能都比较单一。

缺点

  1. 对象结构变化很困难
    不适用于对象结构中的类经常变化的情况,因为对象结构发生了改变,访问者的接口和访问者的实现都要发生相应的改变,代价太高。

  2. 破坏封装
    访问者模式通常需要对象结构开放内部数据给访问者和ObjectStructrue,这破坏了对象的封装性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值