定義
- 將數據結構和對數據結構的操作分離。
使用場景
- 穩定的數據結構和易變的操作耦合問題。
- 需要對一個對象結構中的對象進行很多不同的並且不相關的操作,而需要避免這些操作“污染”這些對象的類,也不希望在增加新操作時修改這些類。
UML圖
代碼實現
代碼來源:https://www.jianshu.com/p/1f1049d0a0f4
年底,CEO和CTO開始評定員工一年的工作績效,員工分爲工程師和經理,CTO關注工程師的代碼量、經理的新產品數量;CEO關注的是工程師的KPI和經理的KPI以及新產品數量。
由於CEO和CTO對於不同員工的關注點是不一樣的,這就需要對不同員工類型進行不同的處理。訪問者模式此時可以派上用場了。
// 員工基類
public abstract class Staff {
public String name;
public int kpi;// 員工KPI
public Staff(String name) {
this.name = name;
kpi = new Random().nextInt(10);
}
// 核心方法,接受Visitor的訪問
public abstract void accept(Visitor visitor);
}
// 工程師
public class Engineer extends Staff {
public Engineer(String name) {
super(name);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
// 工程師一年的代碼數量
public int getCodeLines() {
return new Random().nextInt(10 * 10000);
}
}
// 經理
public class Manager extends Staff {
public Manager(String name) {
super(name);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
// 一年做的產品數量
public int getProducts() {
return new Random().nextInt(10);
}
}
// 員工業務報表類(對象結構)
public class BusinessReport {
private List<Staff> mStaffs = new LinkedList<>();
public BusinessReport() {
mStaffs.add(new Manager("經理-A"));
mStaffs.add(new Engineer("工程師-A"));
mStaffs.add(new Engineer("工程師-B"));
mStaffs.add(new Engineer("工程師-C"));
mStaffs.add(new Manager("經理-B"));
mStaffs.add(new Engineer("工程師-D"));
}
/**
* 爲訪問者展示報表
* @param visitor 公司高層,如CEO、CTO
*/
public void showReport(Visitor visitor) {
for (Staff staff : mStaffs) {
staff.accept(visitor);
}
}
}
public interface Visitor {
// 訪問工程師類型
void visit(Engineer engineer);
// 訪問經理類型
void visit(Manager manager);
}
// CEO訪問者
public class CEOVisitor implements Visitor {
@Override
public void visit(Engineer engineer) {
System.out.println("工程師: " + engineer.name + ", KPI: " + engineer.kpi);
}
@Override
public void visit(Manager manager) {
System.out.println("經理: " + manager.name + ", KPI: " + manager.kpi +
", 新產品數量: " + manager.getProducts());
}
}
// CTO訪問者
public class CTOVisitor implements Visitor {
@Override
public void visit(Engineer engineer) {
System.out.println("工程師: " + engineer.name + ", 代碼行數: " + engineer.getCodeLines());
}
@Override
public void visit(Manager manager) {
System.out.println("經理: " + manager.name + ", 產品數量: " + manager.getProducts());
}
}
總結
-
穩定的數據結構和易變的操作耦合問題;將對象本身與對象的訪問操作分離。
-
優點:
– 符合單一職責原則。
– 優秀的擴展性、靈活性。 -
缺點:
– 具體元素對訪問者公佈細節,違反了迪米特原則。
– 違反了依賴倒置原則,依賴了具體類,沒有依賴抽象。 -
使用場景:
– 一個對象結構(BusinessReport )包含多個類型(manager、Engineer )的對象,希望對這些對象實施一些依賴其具體類型的操作。不同類型的對象可以有不同的訪問操作。
– 需要對一個對象結構中的對象進行很多不同的並且不相關的操作,而且需要避免讓這些操作“污染”這些對象的類,也不希望在增加新操作時修改這些類。