【Java设计模式】· 访问者模式(Visitor Pattern)

1.访问者模式:模式的优点在于保护了被访元素的信息完整性,user只需要通过第三方(objectstructre结构体)就可以完成一个访问过程。而且,被访问的元素可以随时从结构体内增加或删除,也体现了访问者模式的易扩展性。


2. 访问者模式据说是设计模式里面最难懂的,但我觉得最难的还是动态代理模式。那么接下来说一下访问者模式的"难懂"在哪儿?     为了保护"被访问者"的信息,访问者模式将 "访问者"   与  "被访问者" 之间用一个objectstructre类隔开,user只需把访问者通过结构体的accept()函数就可以访问到objectstructre结构体里面的全部被访元素,而visitor和element之间的来回调用函数,就是访问者模式里面最难懂的。



Visitor:访问者抽象类

ConcretVisitor:访问者具体类

Element:被访者抽象类

ConcreteElement:被访者具体类

ObjectStruture:存储被访者 和 接收访问者的类



3.例子:假设 周杰伦 和 梅西 要去买房子,那么他们将去参观三间房子houseA,houseB和houseC. 接下来看代码实现。



访问者的抽象类,声明3个重载的方法,分别接收houseA,B,C三个对象,getVisitorName()函数返回访问者名字

package pers.reus.model.visitor.impl;

import pers.reus.model.element.HouseA;
import pers.reus.model.element.HouseB;
import pers.reus.model.element.HouseC;
//访问者的抽象类
public abstract class Visitor {
	//分别访问A,B,C
	public abstract void visit(HouseA h);
	public abstract void visit(HouseB h);
	public abstract void visit(HouseC h);
	//获得自身(访问者)的名字
	public abstract String getVisitorName();
}


被访问元素的抽象类,2个函数,分别是接收访问者的函数是展示自身信息的函数

package pers.reus.model.element.impl;

import pers.reus.model.visitor.impl.Visitor;

//被访问者的抽象类
public abstract class Element {
	//accept()接受访问者
	public abstract void accept(Visitor v);
	//showMySelf()展示自身信息
	public abstract void showMySelf(Visitor v);
}


被访问元素的具体实现,当调用accept时,函数内会调用访问者类的visit函数,而visit函数又会再调用houseA类的showMySelf函数,这就是访问者模式里面最难懂的部分,因为这个部分最终目的是调用showMySelf(),但是却经过2次来回的调用。

package pers.reus.model.element;

import pers.reus.model.element.impl.Element;
import pers.reus.model.visitor.impl.Visitor;

public class HouseA extends Element{
	//展示自身信息
	public void showMySelf(Visitor v) {
		// TODO Auto-generated method stub
		System.out.println(v.getVisitorName() + " 参观了 " + " HouseA");
	}
	//接受访问者,并调用访问者里面的visit()函数来访问自身
	public void accept(Visitor v) {
		// TODO Auto-generated method stub
		v.visit(this);
	}

}


houseB和houseA的代码完全一样。

package pers.reus.model.element;

import pers.reus.model.element.impl.Element;
import pers.reus.model.visitor.impl.Visitor;

public class HouseB extends Element{
	//展示自身信息
	public void showMySelf(Visitor v) {
		// TODO Auto-generated method stub
		System.out.println(v.getVisitorName() + " 参观了 " + " HouseB");
	}
	//接受访问者,并调用访问者里面的visit()函数来访问自身
	public void accept(Visitor v) {
		// TODO Auto-generated method stub
		v.visit(this);
	}

}


访问者的具体实现类,继承父类三个具体方法,这样可以针对性去访问三个被访元素,注:如果被visit()函数里面的houseA,houseB等换成Element是不能运行的,必须换成具体的实现类

package pers.reus.model.visitor;

import pers.reus.model.element.HouseA;
import pers.reus.model.element.HouseB;
import pers.reus.model.element.HouseC;
import pers.reus.model.visitor.impl.Visitor;

public class JayChou extends Visitor{
	
	//面对不同的被访问者,有他们的特定函数去访问那他们
	public void visit(HouseA h) {
		// TODO Auto-generated method stub
		h.showMySelf(this);
	}

	public void visit(HouseB h) {
		// TODO Auto-generated method stub
		h.showMySelf(this);
	}

	public void visit(HouseC h) {
		// TODO Auto-generated method stub
		h.showMySelf(this);
	}
	//返回自身名字
	public String getVisitorName(){
		return "JayChou";
	}

}


结构体ObjectStructure,他在作用就是1.接收被访元素和删除被访元素    2.帮助访问者去 访问 被访元素。accept()函数里面调用了element里面的accpet(),只要调试一次就懂了

package pers.reus.model.Structure;

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

import pers.reus.model.element.impl.Element;
import pers.reus.model.visitor.impl.Visitor;
//存储被访问的element的结构体ObjectStructure
public class ObjectStructure
{
	//用List存下对象Element
    private final List<Element> elements = new ArrayList<Element>();
    
    //增加Element的函数
    public void addElement(final Element e)
    {
        elements.add(e);
    }

    //删除Element的函数
    public void removeElement(final Element e)
    {
        elements.remove(e);
    }

    //接受访问者,并带领访问者去访问所有存在List里面的Element
    public void accept(final Visitor visitor)
    {
        for (final Element e : elements)
        {
            e.accept(visitor);
        }
    }
}

最后就是client类的测试,1.声明结构体  2.声明被访元素  3.被访元素放入结构体内 4.声明访问者  5.结构体接收访问者,"带" 访问者去访问所有存储在结构体内的被访元素

package pers.reus.model.client;

import pers.reus.model.Structure.ObjectStructure;
import pers.reus.model.element.HouseA;
import pers.reus.model.element.HouseB;
import pers.reus.model.element.HouseC;
import pers.reus.model.element.impl.Element;
import pers.reus.model.visitor.JayChou;
import pers.reus.model.visitor.Messi;
import pers.reus.model.visitor.impl.Visitor;

public class VisitorPatternClient {

	public static void main(String[] args) {
		//声明存储被访问的element的结构体
		ObjectStructure o = new ObjectStructure();
		//声明3个被访问者()
		Element houseA = new HouseA();
		Element houseB = new HouseB();
		Element houseC = new HouseC();
		//把被访问者加入结构体中
		o.addElement(houseA);
		o.addElement(houseB);
		o.addElement(houseC);
		//声明2个访问者,周杰伦和梅西
		Visitor JayChou = new JayChou();
		Visitor Messi = new Messi();
		//通过结构体让访问者访问所有element
		o.accept(JayChou);
		o.accept(Messi);
		
	}

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值