首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

訪問者模式深度解析:雙分派機制與編譯器前端實戰應用

     編輯:Java 綜合教學

模式動機:數據結構與操作分離

訪問者模式將作用於數據結構的操作封裝為獨立的 Visitor 類,使新增操作無需修改數據結構類,符合開閉原則。核心角色:

  • Visitor:抽象訪問者,聲明多個重載 visit(ConcreteElement)
  • ConcreteVisitor:具體操作實現(如打印、統計、導出)
  • Element:抽象元素,定義 accept(Visitor) 授權入口
  • ConcreteElement:實現 accept(v) { v.visit(this); }(雙分派關鍵)
  • ObjectStructure:容納異構元素集合(如 List),提供遍歷入口

基礎實現:簡歷篩選系統


// 元素體系
abstract class Student {
    private String name, university, rating;
    // getter/setter 省略
    public abstract void accept(Visitor visitor);
}
class Bachelor extends Student {
    public void accept(Visitor v) { v.visit(this); }
}
class College extends Student {
    public void accept(Visitor v) { v.visit(this); }
}

// 訪問者接口
interface Visitor {
    void visit(Bachelor b);
    void visit(College c);
}

// 具體訪問者:打印簡歷
class ShowVisitor implements Visitor {
    public void visit(Bachelor b) {
        System.out.println("本科生: " + b.getName());
        printDetail(b);
    }
    public void visit(College c) {
        System.out.println("專科生: " + c.getName());
        printDetail(c);
    }
    private void printDetail(Student s) { ... }
}

// 具體訪問者:統計本科生數量
class SumVisitor implements Visitor {
    private int bachelorCount = 0;
    public void visit(Bachelor b) { bachelorCount++; }
    public void visit(College c) { /* 忽略 */ }
    public int getCount() { return bachelorCount; }
}

// 客戶端
List<Student> list = Arrays.asList(new Bachelor(), new College());
Visitor show = new ShowVisitor(), sum = new SumVisitor();
for (Student s : list) {
    s.accept(show);
    s.accept(sum);
}
System.out.println("本科生總數: " + sum.getCount());

Visitor vs Iterator 核心差異

維度VisitorIterator
訪問對象類型異構(不同 ConcreteElement)同構(同一接口/基類)
依賴關係依賴具體實現(違反 DIP)依賴抽象接口
擴展性新增操作易(新 Visitor),新增元素難(改接口)新增元素易,新增操作難(違反 OCP)
適用場景數據結構穩定、操作頻繁變化數據結構變化、操作固定

雙分派機制深度解析

單分派

Java 單分派 = 靜態重載(編譯期根據參數靜態類型綁定)+ 動態分派(運行期根據接收者實際類型綁定)。普通方法調用 obj.method(arg) 僅根據 obj 動態分派。

雙分派

訪問者模式通過兩次動態分派實現「操作隨訪問者類型與元素類型雙重變化」:

  1. element.accept(visitor) → 根據 element 實際類型調用 Bachelor.accept() 或 College.accept()
  2. visitor.visit(this) → 根據 visitor 實際類型調用 ShowVisitor.visit(Bachelor) 或 SumVisitor.visit(Bachelor)

編譯器靜態綁定保證 visit(this) 參數類型為具體元素類型,從而選中正確重載版本。

實戰場景:Javac 編譯器前端

Javac 詞法/語法分析生成 AST(抽象語法樹),後續語義分析、數據流分析、插糖、字節碼生成等階段均採用 Visitor 模式遍歷 AST:

  • TreeScanner:基礎遍歷器,空操作
  • TreeVisitor:語義分析(類型檢查、符號表填充)
  • Flow:數據流分析(確定賦值、到達性)
  • Lower:插糖(Lambda、switch 表達式、記錄類降級)
  • Gen:字節碼生成

AST 節點(JCTree 子類)結構穩定,分析任務隨 JDK 版本頻繁擴展,完美契合「數據結構固定、操作易變」特征。

優缺點總結與選型建議

優點:單一職責、開閉原則(新增操作)、集中相關行為、可跨層級訪問(如遍歷組合模式樹)。
缺點:違反依賴倒置(依賴具體元素)、新增元素類需修改 Visitor 接口及所有實現、破壞封裝(需暴露內部狀態給 Visitor)。

適用判斷:若對象結構很少變化,但經常需要在其上定義新操作(報導、導出、分析、優化),優先考慮 Visitor;若結構頻繁增減,改用解释器模式或直接在元素類中添加方法。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved