-
目的是:
封裝一些施加于某種數(shù)據(jù)結(jié)構(gòu)元素之上的操作,一旦這些操作改變,接受這個(gè)操作的數(shù)據(jù)結(jié)構(gòu)則可以保持不變
何時(shí)使用:需要對一個(gè)對象結(jié)構(gòu)中的對象進(jìn)行很多不同的并且不相關(guān)的操作,而需要避免讓這些操作"污染"這些對象的類,使用訪問者模式將這些封裝到類中
Problem:如何針對保存有不同類型對象的聚集采取某種操作?
用if幕垦?
訪問者模式適用于 數(shù)據(jù)結(jié)構(gòu)不確定的情況,它把數(shù)據(jù)結(jié)構(gòu)和操作之間的耦合解脫開傅联。
使用場景: 1先改、對象結(jié)構(gòu)中對象對應(yīng)的類很少改變(也就是Node很少改變),但經(jīng)常需要在此對象結(jié)構(gòu)上定義新的操作(也就是經(jīng)常要增加Visitor)
-
上類圖:
訪問者角色.png 優(yōu)點(diǎn):
將有關(guān)的行為集中到一個(gè)訪問者對象中,而不是分散到一個(gè)個(gè)節(jié)點(diǎn)類中,行為集中了,相關(guān)的操作狀態(tài)(類似屬性)也積累在自己的內(nèi)部,而不是分散到很多對象中,這是有利于維護(hù)的.缺點(diǎn):
如果要增加一個(gè)新的節(jié)點(diǎn)都要在抽象訪問者角色中增加一個(gè)新的抽象操作.代碼示例:
- 定義一個(gè)訪問者訪問的接口類,抽象節(jié)點(diǎn)角色
/**
* FileName :ComputerPart
* Author :zengzhijun
* Date : 2018/5/28 15:34
* Description:
*/
package com.byedbl.visitor.sample2.entity;
import com.byedbl.visitor.sample2.visitor.ComputerPartVisitor;
public interface ComputerPart {
public void accept(ComputerPartVisitor computerPartVisitor);
}
- 實(shí)現(xiàn)4個(gè)具體節(jié)點(diǎn)
/**
* FileName :Keyboard
* Author :zengzhijun
* Date : 2018/5/28 15:34
* Description:
*/
package com.byedbl.visitor.sample2.entity;
import com.byedbl.visitor.sample2.visitor.ComputerPartVisitor;
public class Keyboard implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
/**
* FileName :Monitor
* Author :zengzhijun
* Date : 2018/5/28 15:35
* Description:
*/
package com.byedbl.visitor.sample2.entity;
import com.byedbl.visitor.sample2.visitor.ComputerPartVisitor;
public class Monitor implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
/**
* FileName :Mouse
* Author :zengzhijun
* Date : 2018/5/28 15:35
* Description:
*/
package com.byedbl.visitor.sample2.entity;
import com.byedbl.visitor.sample2.visitor.ComputerPartVisitor;
public class Mouse implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
/**
* FileName :Computer
* Author :zengzhijun
* Date : 2018/5/28 15:35
* Description:
*/
package com.byedbl.visitor.sample2.entity;
import com.byedbl.visitor.sample2.visitor.ComputerPartVisitor;
public class Computer implements ComputerPart {
ComputerPart[] parts;
public Computer(){
parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()};
}
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
for (int i = 0; i < parts.length; i++) {
parts[i].accept(computerPartVisitor);
}
computerPartVisitor.visit(this);
}
}
- 定義訪問者抽象接口
/**
* FileName :ComputerPartVisitor
* Author :zengzhijun
* Date : 2018/5/28 15:36
* Description:
*/
package com.byedbl.visitor.sample2.visitor;
import com.byedbl.visitor.sample2.entity.Computer;
import com.byedbl.visitor.sample2.entity.Keyboard;
import com.byedbl.visitor.sample2.entity.Monitor;
import com.byedbl.visitor.sample2.entity.Mouse;
public interface ComputerPartVisitor {
public void visit(Computer computer);
public void visit(Mouse mouse);
public void visit(Keyboard keyboard);
public void visit(Monitor monitor);
}
- 實(shí)現(xiàn)訪問者接口
/**
* FileName :ComputerPartDisplayVisitor
* Author :zengzhijun
* Date : 2018/5/28 15:36
* Description:
*/
package com.byedbl.visitor.sample2.visitor;
import com.byedbl.visitor.sample2.entity.Computer;
import com.byedbl.visitor.sample2.entity.Keyboard;
import com.byedbl.visitor.sample2.entity.Monitor;
import com.byedbl.visitor.sample2.entity.Mouse;
public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
@Override
public void visit(Computer computer) {
System.out.println("Displaying Computer.");
}
@Override
public void visit(Mouse mouse) {
System.out.println("Displaying Mouse.");
}
@Override
public void visit(Keyboard keyboard) {
System.out.println("Displaying Keyboard.");
}
@Override
public void visit(Monitor monitor) {
System.out.println("Displaying Monitor.");
}
}
- 客戶端用法
/**
* FileName :VisitorPatternDemo
* Author :zengzhijun
* Date : 2018/5/28 15:36
* Description:
*/
package com.byedbl.visitor.sample2;
import com.byedbl.visitor.sample2.entity.Computer;
import com.byedbl.visitor.sample2.entity.ComputerPart;
import com.byedbl.visitor.sample2.entity.Mouse;
import com.byedbl.visitor.sample2.visitor.ComputerPartDisplayVisitor;
/**
*
* <pre>
* 備受爭議的訪問者模式
* 因?yàn)樵黾右粋€(gè)Node節(jié)點(diǎn)就要在Visitor節(jié)點(diǎn)中(這里是 ComputerPartVisitor)增加一個(gè)方法支持它
* 如果已經(jīng)實(shí)現(xiàn)了很多Visitor那不是很坑爹?當(dāng)然在java8里面可以加一個(gè)默認(rèn)的方法了,情況可能好一點(diǎn)
* 但是還是不能掩蓋其違反了開閉原則
*
* 但是作為實(shí)用主義來講,只要管用,理論就可以先一邊呆著去...
* 畢竟像中國的代碼,if else if 幾百行 也不是沒見過的
*
* @author : zengzhijun
* @date : 2018/5/28 15:51
**/
public class VisitorPatternDemo {
public static void main(String[] args) {
ComputerPart computer = new Computer();
computer.accept(new ComputerPartDisplayVisitor());
System.out.println("--------------");
ComputerPart computerPart = new Mouse();
computerPart.accept(new ComputerPartDisplayVisitor());
}
}
這個(gè)例子很形象,電腦組件就這幾個(gè),但是不同的人用來干不同的事,也就是滿足對象結(jié)構(gòu)中對象對應(yīng)的類很少改變(也就是Node很少改變)蒸走,但經(jīng)常需要在此對象結(jié)構(gòu)上定義新的操作(也就是經(jīng)常要增加Visitor)