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