# 拜訪者模式 Visitor ## 個人思路 資料結構會有一個接受訪客的方法,通常會直接使用interface 為什麼要這樣做? 因為這樣資料結構只寫接受訪客的method就好。 那如果要使用到該資料結構時,只要寫好訪客的功能,接著在資料結構的接受訪客那邊把要使用的訪客的功能當作參數丟進去即可。 總之就是**把處理從資料結構分離出來**不去修改資料結構 ## 角色 **Visitor (訪客) 參與者** Visitor 建立功能的介面。原始碼會實作在 ConcreteVisitor 那裡。 **ConcreteVisitor 參與者** ConcreteVisitor 是實作 Visitor 的介面。它實作 visit(XXXX) 格式的方法,然後***敘述各個 ConcreteAcceptor 的處理***。 **Acceptor 參與者** Acceptor 是表示 Visitor 訪問對象的參與者。宣告接受訪客的 accept 方法。Visitor 則被傳遞給 accept 方法的引數。例如 Acceptor 介面。 **ConcreteAcceptor 參與者** ConcreteAcceptor 實作 Acceptor 的介面。 ![](https://i.imgur.com/gxcS58R.png) ## 範例 ```java= //acceptor介面 public interface CarElement{ public void accept(final CarElementVisitor visitor); } //visitor interface CarElementVisitor { void visit(final Body body); void visit(final Car car); void visit(final Engine engine); void visit(final Wheel wheel); } class Body implements CarElement{ public void accept(final CarElementVisitor visitor){ visitor.visit(this); } } class Engine implements CarElement{ public void accept(final ICarElementVisitor visitor){ visitor.visit(this); } } class Wheel implements CarElement{ private String name; public Wheel(final String name){ this.name = name; } public String getName(){ return this.name; } public void accept(final CarElementVisitor visitor){ visitor.visit(this); } } class Car implements CarElement{ private CarElement[] mElements; public Car(){ this.mElements = new CarElement[] { new Wheel("front left"), new Wheel("front right"), new Wheel("back left"), new Wheel("back right"), new Body(), new Engine() }; } public void accept(final CarElementVisitor visitor){ for(final mElements elem : elements){ elem.accept(visitor); } visitor.visit(this); } } //兩個concreteVistor 有兩個不同的功能 class CarElementDoVisitor implements CarElementVisitor { public void visit(final Body body) { System.out.println("Moving my body"); } public void visit(final Car car) { System.out.println("Starting my car"); } public void visit(final Wheel wheel) { System.out.println("Kicking my " + wheel.getName() + " wheel"); } public void visit(final Engine engine) { System.out.println("Starting my engine"); } } class CarElementPrintVisitor implements ICarElementVisitor { public void visit(final Body body) { System.out.println("Visiting body"); } public void visit(final Car car) { System.out.println("Visiting car"); } public void visit(final Engine engine) { System.out.println("Visiting engine"); } public void visit(final Wheel wheel) { System.out.println("Visiting " + wheel.getName() + " wheel"); } } public class VisitorDemo { public static void main(final String[] arguments) { final CarElement car = new Car(); // 基本上會依據不同用途而建立不同的具象 Visitor, // 因此同一個 car 會因為不同的 Visitor 而有 // 不同執行結果 car.accept(new CarElementPrintVisitor()); car.accept(new CarElementDoVisitor()); } } ``` ## Differences between Strategy and Visitor 在Strategy中,我們只讓一個對象執行注入的策略。(1:N) 但在Visitor中,我們可以讓很多對象依序執行注入的策略。(N:N)
{"metaMigratedAt":"2023-06-16T11:21:19.419Z","metaMigratedFrom":"YAML","title":"拜訪者模式 Visitor","breaks":true,"contributors":"[{\"id\":\"63f87db7-492b-4b20-85a8-f9c9ecb34124\",\"add\":113,\"del\":1},{\"id\":\"1880e957-c482-42c0-815b-4a0ded0c27a0\",\"add\":4361,\"del\":1095},{\"id\":\"82eaa412-2ff3-4bfe-bbd7-5ff190dd3326\",\"add\":30,\"del\":0}]"}
Expand menu