訪問者模式
Reference
[1] bugstack.cn/md/develop/…
[2] c.biancheng.net/view/1397.h…
[3] refactoringguru.cn/design-patt…
[4] cmsblogs.com/article/140…
什么是訪問者模式
訪問者要解決的核心事項是,在一個穩定的資料結構下,例如用戶資訊、雇員資訊等,增加易變的業務訪問邏輯,為了增強擴展性,將這兩部分的業務解耦的一種設計模式,
說白了訪問者模式的核心在于同一個事物不同視角下的訪問資訊不同,比如看一場籃球比賽,外行人關注的是是否進球,內行人看的是球員的技術,球隊的配合等,
訪問者模式結構

- 訪問者 (Visitor) 介面宣告了一系列以物件結構的具體元素為引數的訪問者方法, 如果編程語言支持多載, 這些方法的名稱可以是相同的, 但是其引數一定是不同的,
- 具體訪問者 (Concrete Visitor) 會為不同的具體元素類實作相同行為的幾個不同版本,
- 元素 (Element) 介面宣告了一個方法來 “接收” 訪問者, 該方法必須有一個引數被宣告為訪問者介面型別,
- 具體元素 (Concrete Element) 必須實作接收方法, 該方法的目的是根據當前元素類將其呼叫重定向到相應訪問者的方法, 請注意, 即使元素基類實作了該方法, 所有子類都必須對其進行重寫并呼叫訪問者物件中的合適方法,
- 客戶端 (Client) 通常會作為集合或其他復雜物件 (例如一個組合樹) 的代表, 客戶端通常不知曉所有的具體元素類, 因為它們會通過抽象介面與集合中的物件進行互動,
場景
我們模擬校園中有學生和老師兩種身份的用戶,那么對于家長和校長關心的角度來看,他們的視角是不同的,家長更關心孩子的成績和老師的能力,校長更關心老師所在班級學生的人數和升學率{此處模擬的},
分析一下這個例子:
- 訪問者 Visitor,作為 visitor 去訪問 accept 介面,進行自己想要的操作
- 校長
- 家長
- 元素 User,需要對外提供 accept 可訪問的介面
- 學生 具體元素
- 老師 具體元素

// 基礎用戶資訊
public abstract class User {
public String name; // 姓名
public String identity; // 身份;重點班、普通班 | 特級教師、普通教師、實習教師
public String clazz; // 班級
public User(String name, String identity, String clazz) {
this.name = name;
this.identity = identity;
this.clazz = clazz;
}
// 核心訪問方法
public abstract void accept(Visitor visitor);
}
public class Teacher extends User {
public Teacher(String name, String identity, String clazz) {
super(name, identity, clazz);
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
// 升本率
public double entranceRatio() {
return BigDecimal.valueOf(Math.random() * 100).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
}
}
public class Student extends User {
public Student(String name, String identity, String clazz) {
super(name, identity, clazz);
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
public int ranking() {
return (int) (Math.random() * 100);
}
}
public interface Visitor {
// 訪問學生資訊
void visit(Student student);
// 訪問老師資訊
void visit(Teacher teacher);
}
public class Principal implements Visitor {
private Logger logger = LoggerFactory.getLogger(Principal.class);
public void visit(Student student) {
logger.info("學生資訊 姓名:{} 班級:{}", student.name, student.clazz);
}
public void visit(Teacher teacher) {
logger.info("學生資訊 姓名:{} 班級:{} 升學率:{}", teacher.name, teacher.clazz, teacher.entranceRatio());
}
}
public class Parent implements Visitor {
private Logger logger = LoggerFactory.getLogger(Parent.class);
public void visit(Student student) {
logger.info("學生資訊 姓名:{} 班級:{} 排名:{}", student.name, student.clazz, student.ranking());
}
public void visit(Teacher teacher) {
logger.info("老師資訊 姓名:{} 班級:{} 級別:{}", teacher.name, teacher.clazz, teacher.identity);
}
}
public class DataView {
List<User> userList = new ArrayList<User>();
public DataView() {
userList.add(new Student("謝飛機", "重點班", "一年一班"));
userList.add(new Student("windy", "重點班", "一年一班"));
userList.add(new Student("大毛", "普通班", "二年三班"));
userList.add(new Student("Shing", "普通班", "三年四班"));
userList.add(new Teacher("BK", "特級教師", "一年一班"));
userList.add(new Teacher("娜娜Goddess", "特級教師", "一年一班"));
userList.add(new Teacher("dangdang", "普通教師", "二年三班"));
userList.add(new Teacher("澤東", "實習教師", "三年四班"));
}
// 展示
public void show(Visitor visitor) {
for (User user : userList) {
user.accept(visitor);
}
}
}
@Test
public void test(){
DataView dataView = new DataView();
logger.info("\r\n家長視角訪問:");
dataView.show(new Parent()); // 家長
logger.info("\r\n校長視角訪問:");
dataView.show(new Principal()); // 校長
}
復制代碼
測驗結果
23:00:39.726 [main] INFO org.itstack.demo.design.test.ApiTest -
家長視角訪問:
23:00:39.730 [main] INFO o.i.demo.design.visitor.impl.Parent - 學生資訊 姓名:謝飛機 班級:一年一班 排名:62
23:00:39.730 [main] INFO o.i.demo.design.visitor.impl.Parent - 學生資訊 姓名:windy 班級:一年一班 排名:51
23:00:39.730 [main] INFO o.i.demo.design.visitor.impl.Parent - 學生資訊 姓名:大毛 班級:二年三班 排名:16
23:00:39.730 [main] INFO o.i.demo.design.visitor.impl.Parent - 學生資訊 姓名:Shing 班級:三年四班 排名:98
23:00:39.730 [main] INFO o.i.demo.design.visitor.impl.Parent - 老師資訊 姓名:BK 班級:一年一班 級別:特級教師
23:00:39.730 [main] INFO o.i.demo.design.visitor.impl.Parent - 老師資訊 姓名:娜娜Goddess 班級:一年一班 級別:特級教師
23:00:39.730 [main] INFO o.i.demo.design.visitor.impl.Parent - 老師資訊 姓名:dangdang 班級:二年三班 級別:普通教師
23:00:39.730 [main] INFO o.i.demo.design.visitor.impl.Parent - 老師資訊 姓名:澤東 班級:三年四班 級別:實習教師
23:00:39.730 [main] INFO org.itstack.demo.design.test.ApiTest -
校長視角訪問:
23:00:39.731 [main] INFO o.i.d.design.visitor.impl.Principal - 學生資訊 姓名:謝飛機 班級:一年一班
23:00:39.731 [main] INFO o.i.d.design.visitor.impl.Principal - 學生資訊 姓名:windy 班級:一年一班
23:00:39.731 [main] INFO o.i.d.design.visitor.impl.Principal - 學生資訊 姓名:大毛 班級:二年三班
23:00:39.731 [main] INFO o.i.d.design.visitor.impl.Principal - 學生資訊 姓名:Shing 班級:三年四班
23:00:39.733 [main] INFO o.i.d.design.visitor.impl.Principal - 學生資訊 姓名:BK 班級:一年一班 升學率:70.62
23:00:39.733 [main] INFO o.i.d.design.visitor.impl.Principal - 學生資訊 姓名:娜娜Goddess 班級:一年一班 升學率:23.15
23:00:39.734 [main] INFO o.i.d.design.visitor.impl.Principal - 學生資訊 姓名:dangdang 班級:二年三班 升學率:70.98
23:00:39.734 [main] INFO o.i.d.design.visitor.impl.Principal - 學生資訊 姓名:澤東 班級:三年四班 升學率:90.14
Process finished with exit code 0
復制代碼
- 通過測驗結果可以看到,家長和校長的訪問視角同步,資料也是差異化的,
- 家長視角看到學生的排名;
排名:62、排名:51、排名:16、排名:98, - 校長視角看到班級升學率;
升學率:70.62、升學率:23.15、升學率:70.98、升學率:90.14, - 通過這樣的測驗結果,可以看到訪問者模式的初心和結果,在適合的場景運用合適的模式,非常有利于程式開發
適用場景
- 物件結構中物件對應的類很少改變,但經常需要在此物件結構上定義新的操作,
- 需要對一個物件結構中的物件進行很多不同的并且不相關的操作,而需要避免讓這些操作"污染"這些物件的類,也不希望在增加新操作時修改這些類
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/387273.html
標籤:區塊鏈
