java的visitor模式_java设计模式(二十一)访问者模式(Visitor)
介紹
訪問者模式(Visitor Pattern):表示一個作用于某對象結構中的各元素的操作,它使我們可以在不改變各元素的類的前提下定義作用于這些元素的新操作。訪問者模式是一種對象行為型模式。
簡單來說,訪問者模式就是一種分離對象數據結構與行為的方法,通過這種分離,可達到為一個被訪問者動態添加新的操作而無需做其它的修改的效果。
關系圖:
Visitor接口:存放要訪問的對象1
2
3public interface{
public void visit(Subject sub);
}
實現類:1
2
3
4
5
6public class MyVisitor implements{
public void visit(Subject sub){
System.out.println("visit the subject:"+sub.getSubject());
}
}
Subject接口:accept方法,接受將要訪問它的對象,getSubject()獲取將要被訪問的屬性1
2
3
4public interface Subject{
public void accept(Visitor visitor);
public String getSubject();
}
實現類:1
2
3
4
5
6
7
8
9
10
11public class MySubject implements Subject{
public void accept(Visitor visitor){
visitor.visit(this);
}
public String getSubject(){
return "love";
}
}
測試類:1
2
3
4
5
6
7
8public class Test{
public static void main(String[] args){
Visitor visitor = new MyVisitor();
Subject sub = new MySubject();
sub.accept(visitor);
}
}
該模式適用場景:如果我們想為一個現有的類增加新功能,不得不考慮幾個事情:新功能會不會與現有功能出現兼容性問題?
以后會不會再需要添加?
如果類不允許修改代碼怎么辦?
面對這些問題,最好的解決方法就是使用訪問者模式,訪問者模式適用于數據結構相對穩定的系統,把數據結構和算法解耦
擴展
1. 模式動機在實際使用時,對同一集合對象的操作并不是唯一的,對相同的元素對象可能存在多種不同的操作方式。而且這些操作方式并不穩定,可能還需要增加新的操作,以滿足新的業務需求。此時,訪問者模式就是一個值得考慮的解決方案。
訪問者模式的目的是封裝一些施加于某種數據結構元素之上的操作,一旦這些操作需要修改的話,接受這個操作的數據結構可以保持不變。為不同類型的元素提供多種訪問操作方式,且可以在不修改原有系統的情況下增加新的操作方式。
2. 模式結構
訪問者模式包含如下角色:Vistor: 抽象訪問者
ConcreteVisitor: 具體訪問者
Element: 抽象元素
ConcreteElement: 具體元素
ObjectStructure: 對象結構
3. 模式分析訪問者模式中對象結構存儲了不同類型的元素對象,以供不同訪問者訪問。
訪問者模式包括兩個層次結構,一個是訪問者層次結構,提供了抽象訪問者和具體訪問者,一個是元素層次結構,提供了抽象元素和具體元素。
相同的訪問者可以以不同的方式訪問不同的元素,相同的元素可以接受不同訪問者以不同訪問方式訪問。在訪問者模式中,增加新的訪問者無須修改原有系統,系統具有較好的可擴展性
典型的抽象訪問者類代碼:1
2
3
4
5
6
7public abstract class{
public abstract void visit(ConcreteElementA elementA);
public abstract void visit(ConcreteElementB elementB);
public void visit(ConcreteElementC elementC){
//元素ConcreteElementC操作代碼
}
}
典型的具體訪問者類代碼:1
2
3
4
5
6
7
8public class ConcreteVisitor extends{
public void visit(ConcreteElementA elementA){
//元素ConcreteElementA操作代碼
}
public void visit(ConcreteElementB elementB){
//元素ConcreteElementB操作代碼
}
}
典型的抽象元素類代碼:1
2
3public interface Element{
public void accept(Visitor visitor);
}
具體元素類代碼:1
2
3
4
5
6
7
8
9public class ConcreteElementA implements Element{
public void accept(Visitor visitor){
visitor.visit(this);
}
public void operationA(){
//業務方法
}
}
典型的對象結構類代碼:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public 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);
}
}
4. 適用場景一個對象結構包含很多類型的對象,希望對這些對象實施一些依賴其具體類型的操作。在訪問者中針對每一種具體的類型都提供了一個訪問操作,不同類型的對象可以有不同的訪問操作。
需要對一個對象結構中的對象進行很多不同的并且不相關的操作,而需要避免讓這些操作污染這些對象的類,也不希望在增加新操作時修改這些類。訪問者模式使得我們可以將相關的訪問操作集中起來定義在訪問者類中,對象結構可以被多個不同的訪問者類所使用,將對象本身與對象的訪問操作分離。
對象結構中對象對應的類很少改變,但經常需要在此對象結構上定義新的操作。
5. 模式應用在一些編譯器的設計中運用了訪問者模式,程序代碼是被訪問的對象,它包括變量定義、變量賦值、邏輯運算、算術運算等語句,編譯器需要對代碼進行分析,如檢查變量是否定義、變量是否賦值、算術運算是否合法等,可以將不同的操作封裝在不同的類中,如檢查變量定義的類、檢查變量賦值的類、檢查算術運算是否合法的類,這些類就是具體訪問者,可以訪問程序代碼中不同類型的語句。在編譯過程中除了代碼分析外,還包含代碼優化、空間分配和代碼生成等部分,也可以將每一個不同編譯階段的操作封裝到了跟該階段有關的一個訪問者類中。
在常用的Java XML處理技術DOM4J中,可以通過訪問者模式的方式來讀取并解析XML文檔,VisitorSupport是DOM4J提供的Visitor接口的默認適配器,具體訪問者只需繼承VisitorSupport類即可。1
2
3
4
5
6
7
8public class MyVisitor extends VisitorSupport{
public void visit(Element element){
System.out.println(element.getName());
}
public void visit(Attribute attr){
System.out.println(attr.getName());
}
}
6. 模式擴展與其他模式聯用由于訪問者模式需要對對象結構進行操作,而對象結構本身是一個元素對象的集合,因此訪問者模式經常需要與迭代器模式聯用,在對象結構中使用迭代器來遍歷元素對象。
在訪問者模式中,元素對象可能存在容器對象和葉子對象,因此可以結合組合模式來進行設計。
訪問者模式以一種傾斜的方式支持開閉原則,增加新的訪問者方便,但是增加新的元素很困難。
7. 模式優缺點優點使得增加新的訪問操作變得很容易。
將有關元素對象的訪問行為集中到一個訪問者對象中,而不是分散到一個個的元素類中。
可以跨過類的等級結構訪問屬于不同的等級結構的元素類。
讓用戶能夠在不修改現有類層次結構的情況下,定義該類層次結構的操作。
缺點增加新的元素類很困難。在訪問者模式中,每增加一個新的元素類都意味著要在抽象訪問者角色中增加一個新的抽象操作,并在每一個具體訪問者類中增加相應的具體操作,違背了開閉原則的要求。
破壞封裝。訪問者模式要求訪問者對象訪問并調用每一個元素對象的操作,這意味著元素對象有時候必須暴露一些自己的內部操作和內部狀態,否則無法供訪問者訪問。
總結
以上是生活随笔為你收集整理的java的visitor模式_java设计模式(二十一)访问者模式(Visitor)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux中常用安装程序的方法,Linu
- 下一篇: 有两个python怎么停用其中一_pyt