【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);
		
	}

}



發佈了26 篇原創文章 · 獲贊 29 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章