1. 聯(lián)合組合模式
//抽象的組件對(duì)象,相當(dāng)于訪問者模式中的元素對(duì)象
public abstract class Component {//接受訪問者的訪問 public abstract void
accept(Visitor visitor
);//向組合對(duì)象中加入組件對(duì)象 public void addChild(Component child) {// 缺省的實(shí)現(xiàn),拋出例外,因?yàn)槿~子對(duì)象沒有這個(gè)功能,或者子組件沒有實(shí)現(xiàn)這個(gè)功能throw new
UnsupportedOperationException("對(duì)象不支持這個(gè)功能"); }//從組合對(duì)象中移出某個(gè)組件對(duì)象 public void removeChild(Component child) {// 缺省的實(shí)現(xiàn),拋出例外,因?yàn)槿~子對(duì)象沒有這個(gè)功能,或者子組件沒有實(shí)現(xiàn)這個(gè)功能throw new
UnsupportedOperationException("對(duì)象不支持這個(gè)功能"); }// 返回某個(gè)索引對(duì)應(yīng)的組件對(duì)象 public Component getChildren(int index) {throw new
UnsupportedOperationException("對(duì)象不支持這個(gè)功能");}
}public class Leaf extends Component{public void accept(Visitor visitor) {//回調(diào)訪問者對(duì)象的相應(yīng)方法visitor.
visitLeaf(this
);}private String name =
""; //葉子對(duì)象的名字 public Leaf(String name){this.name = name
;}public String getName() {return name
;}
}//循環(huán)子元素,讓子元素也接受訪問
public class Composite extends Component{public void accept(Visitor visitor) {//回調(diào)訪問者對(duì)象的相應(yīng)方法visitor.
visitComposite(this
);//循環(huán)子元素,讓子元素也接受訪問for(Component c : childComponents){//調(diào)用子對(duì)象接受訪問,變相實(shí)現(xiàn)遞歸c.
accept(visitor
);}}//用來存儲(chǔ)組合對(duì)象中包含的子組件對(duì)象 private List<Component> childComponents = new ArrayList<Component>
(); private String name =
"";//組合對(duì)象的名字 public Composite(String name){this.name = name
;} public void addChild(Component child) {childComponents.
add(child
);}public String getName() {return name
;}
}public interface Visitor {//訪問組合對(duì)象,相當(dāng)于給組合對(duì)象添加訪問者的功能 public void
visitComposite(Composite composite
);//訪問葉子對(duì)象,相當(dāng)于給葉子對(duì)象添加訪問者的功能 public void
visitLeaf(Leaf leaf
);
}public class PrintNameVisitor implements Visitor {public void visitComposite(Composite composite) {//訪問到組合對(duì)象的數(shù)據(jù)System.out.
println("節(jié)點(diǎn):"+composite.
getName());}public void visitLeaf(Leaf leaf) {//訪問到葉子對(duì)象的數(shù)據(jù) System.out.
println("葉子:"+leaf.
getName());}
}public class ObjectStructure {//表示對(duì)象結(jié)構(gòu),可以是一個(gè)組合結(jié)構(gòu) private Component root = null
;public void handleRequest(Visitor visitor){//讓組合對(duì)象結(jié)構(gòu)中的根元素,接受訪問//在組合對(duì)象結(jié)構(gòu)中已經(jīng)實(shí)現(xiàn)了元素的遍歷if(root!=null){root.
accept(visitor
);}}// 傳入組合對(duì)象結(jié)構(gòu) public void setRoot(Component ele){this.root = ele
;}
}public static void main(String[] args) {//定義所有的組合對(duì)象Component root = new
Composite("服裝");Component c1 = new
Composite("男裝");Component c2 = new
Composite("女裝");//定義所有的葉子對(duì)象Component leaf1 = new
Leaf("襯衣");Component leaf2 = new
Leaf("夾克");Component leaf3 = new
Leaf("裙子");Component leaf4 = new
Leaf("套裝");//按照樹的結(jié)構(gòu)來組合組合對(duì)象和葉子對(duì)象root.
addChild(c1
);root.
addChild(c2
);c1.
addChild(leaf1
);c1.
addChild(leaf2
);c2.
addChild(leaf3
);c2.
addChild(leaf4
);//創(chuàng)建ObjectStructureObjectStructure os = new
ObjectStructure();os.
setRoot(root
);//調(diào)用ObjectStructure來處理請(qǐng)求功能Visitor psVisitor = new
PrintNameVisitor();
// root.
accept(psVisitor
); os.
handleRequest(psVisitor
);//或者去掉ObjectStructure //調(diào)用根元素的方法來接受請(qǐng)求功能Visitor psVisitor = new
PrintStructVisitor(); root.
accept(psVisitor
);
}
1.1.有的時(shí)候可以省略O(shè)bjectStructure ,client直接調(diào)用
1.2. 改造版
假設(shè)要輸出下面的結(jié)果:定制“+”、“-”
public class PrintStructVisitor implements Visitor { private String preStr =
"";//用來累計(jì)記錄對(duì)象需要向后退的格public void visitComposite(Composite composite) {//先把自己輸出去System.out.
println(preStr+
"+"+composite.
getName());//如果還包含有子組件,那么就輸出這些子組件對(duì)象if(composite.getChildComponents()!=null){//然后添加一個(gè)空格,表示向后縮進(jìn)一個(gè)空格preStr+=
" "; //輸出當(dāng)前對(duì)象的子對(duì)象了for(Component c : composite.getChildComponents()){//遞歸輸出每個(gè)子對(duì)象c.
accept(this
);}//把循環(huán)子對(duì)象所多加入的一個(gè)退格給去掉preStr = preStr.
substring(0,preStr.
length()-1
);}}public void visitLeaf(Leaf leaf) {//訪問到葉子對(duì)象的數(shù)據(jù) System.out.
println(preStr+
"-"+leaf.
getName());}
}
2. 總結(jié)
2.1 訪問者模式有以下缺點(diǎn)
對(duì)象結(jié)構(gòu)變化很困難
不適用于對(duì)象結(jié)構(gòu)中的類經(jīng)常變化的情況,因?yàn)閷?duì)象結(jié)構(gòu)發(fā)生了改變,訪問者的接口和訪問者的實(shí)現(xiàn)都要發(fā)生相應(yīng)的改變,代價(jià)太高。
破壞封裝
訪問者模式通常需要對(duì)象結(jié)構(gòu)開放內(nèi)部數(shù)據(jù)給訪問者和ObjectStructrue,這破壞了對(duì)象的封裝性。
2.2 訪問者模式的本質(zhì):預(yù)留通路,回調(diào)實(shí)現(xiàn)。
仔細(xì)思考訪問者模式,它的實(shí)現(xiàn)主要是通過預(yù)先定義好調(diào)用的通路,在被訪問的對(duì)象上定義accept方法,在訪問者的對(duì)象上定義visit方法;然后在調(diào)用真正發(fā)生的時(shí)候,通過兩次分發(fā)技術(shù),利用預(yù)先定義好的通路,回調(diào)到訪問者具體的實(shí)現(xiàn)上。
明白了訪問者模式的本質(zhì),就可以在定義一些通用功能,或者設(shè)計(jì)工具類的時(shí)候讓訪問者模式派上大用場(chǎng)。你可以把已經(jīng)實(shí)現(xiàn)好的一些功能作為已有的對(duì)象結(jié)構(gòu),因?yàn)樵诮窈罂赡軙?huì)根據(jù)實(shí)際需要為它們?cè)黾有碌墓δ?#xff0c;甚至希望開放接口來讓其他開發(fā)人員擴(kuò)展這些功能,所以你可以用訪問者模式來設(shè)計(jì),在這個(gè)對(duì)象結(jié)構(gòu)上預(yù)留好通用的調(diào)用通路,在以后添加功能,或者是其他開發(fā)人員來擴(kuò)展的時(shí)候,只需要提供新的訪問者實(shí)現(xiàn),就能夠很好地加入到系統(tǒng)中來了。
2.3 建議在以下情況中選用訪問者模式。
如果想對(duì)一個(gè)對(duì)象結(jié)構(gòu)實(shí)施一些依賴于對(duì)象結(jié)構(gòu)中具體類的操作,可以使用訪問者模式。
如果想對(duì)一個(gè)對(duì)象結(jié)構(gòu)中的各個(gè)元素進(jìn)行很多不同的而且不相關(guān)的操作,為了避免這些操作使類變得雜亂,可以使用訪問者模式。把這些操作分散到不同的訪問者對(duì)象中去,每個(gè)訪問者對(duì)象實(shí)現(xiàn)同一類功能。
如果對(duì)象結(jié)構(gòu)很少變動(dòng),但是需要經(jīng)常給對(duì)象結(jié)構(gòu)中的元素對(duì)象定義新的操作,可以使用訪問者模式。
總結(jié)
以上是生活随笔為你收集整理的《研磨设计模式》chap25 访问者模式Visitor(3)联合组合模式+总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。