軟體設計原則 GRASP 通用職責分配軟體模式 來自 Craig Larman 的軟體設計書《UML 和模式應用》,Larman 在書中提出軟體設計的關鍵任務是職責分配,並提煉總結出 9 種 (5 種核心 +4 種擴展) 軟體職責分配模式,這些模式是比 GoF 設計模式更抽象的元模式。 信息專家 ( ...
訪問者模式(Visitor Pattern)是一種強大的行為型設計模式,它允許你在不改變被訪問對象的類的前提下,定義新的操作和行為。本文將詳細介紹訪問者模式,包括其定義、舉例說明、結構、實現步驟、Java代碼實現、典型應用場景、優缺點、類似模式以及最後的小結。
1 模式的定義
訪問者模式允許你在不修改被訪問對象的類的情況下,定義並封裝一組新的操作。它通常用於處理對象結構中的元素,並能夠在不改變這些元素的類的情況下,為這些元素添加新的操作。這種模式的關鍵思想是將操作與元素分離,使得增加新操作變得相對容易。
2 舉例說明
訪問者模式的思想在日常生活中有許多應用,以下是幾個比較符合訪問者模式且為大家所熟知的例子:
博物館導覽員:在博物館中,導覽員扮演著訪問者的角色。博物館中的藝術品、展品等可以被看作是元素,而導覽員則是具體訪問者。導覽員可以根據參觀者的需求,為他們提供不同的講解、信息或故事,而不需要改變藝術品本身。
旅游團隊:旅游團隊的導游可以被看作是訪問者,而游客可以被視為元素。導游可以根據游客的興趣和需求,提供不同的旅游信息和體驗,而不需要修改景點本身。
電子商務網站的購物車:在電子商務網站中,購物車可以被看作是對象結構,而購買的商品可以被視為元素。不同的訪問者可以執行不同的操作,例如計算總價、生成訂單等,而不需要修改商品類的代碼。
這些例子都展示了訪問者模式的核心思想:允許在不改變元素本身的情況下,為元素執行不同的操作。這種分離關註點的設計模式在實際生活中具有廣泛的應用。
3 結構
訪問者模式由以下主要組件組成:
訪問者(Visitor):定義了要訪問的對象的介面,包括訪問不同類型對象的方法。
具體訪問者(ConcreteVisitor):實現了訪問者介面,定義了針對不同類型對象的具體操作。
元素(Element):定義了接受訪問者訪問的介面,通常包括一個 accept 方法,該方法接受訪問者作為參數。
具體元素(ConcreteElement):實現了元素介面,它包含了 accept 方法的實現,該方法將自身傳遞給訪問者以便進行操作。
對象結構(Object Structure):包含元素的集合,通常提供一個方法來遍歷這些元素,訪問者可以通過該方法訪問元素。
4 實現步驟
實現訪問者模式需要按照以下步驟進行:
定義元素介面(Element),其中包括一個接受訪問者的方法(accept 方法)。
創建具體元素類(ConcreteElement),實現元素介面,並提供具體的操作。
定義訪問者介面(Visitor),其中包括為每個具體元素類型定義的訪問方法。
創建具體訪問者類(ConcreteVisitor),實現訪問者介面,併為每個具體元素類型提供具體的訪問方法。
創建對象結構類(Object Structure),其中包含元素的集合,並提供一個方法用於訪問元素。
在客戶端代碼中,創建具體元素的實例,將它們添加到對象結構中,並創建具體訪問者的實例。
使用訪問者對象來訪問對象結構中的元素,從而執行具體的操作。
5 代碼實現
以下是一個使用Java編寫的訪問者模式的示例代碼:
// Step 1: 定義元素介面
interface Animal {
void accept(Visitor visitor);
}
// Step 2: 創建具體元素類
class Dog implements Animal {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
class Cat implements Animal {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// Step 3: 定義訪問者介面
interface Visitor {
void visit(Dog dog);
void visit(Cat cat);
}
// Step 4: 創建具體訪問者類
class HealthCheckupVisitor implements Visitor {
@Override
public void visit(Dog dog) {
System.out.println("健康檢查狗:" + dog.getClass().getSimpleName());
}
@Override
public void visit(Cat cat) {
System.out.println("健康檢查貓:" + cat.getClass().getSimpleName());
}
}
class InformationDisplayVisitor implements Visitor {
@Override
public void visit(Dog dog) {
System.out.println("展示狗信息:" + dog.getClass().getSimpleName());
}
@Override
public void visit(Cat cat) {
System.out.println("展示貓信息:" + cat.getClass().getSimpleName());
}
}
// Step 5: 創建對象結構類
class Zoo {
private List<Animal> animals = new ArrayList<>();
public void addAnimal(Animal animal) {
animals.add(animal);
}
public void accept(Visitor visitor) {
for (Animal animal : animals) {
animal.accept(visitor);
}
}
}
// Step 6: 客戶端代碼
public class VisitorPatternExample {
public static void main(String[] args) {
Zoo zoo = new Zoo();
zoo.addAnimal(new Dog());
zoo.addAnimal(new Cat());
Visitor healthCheckupVisitor = new HealthCheckupVisitor();
Visitor informationDisplayVisitor = new InformationDisplayVisitor();
zoo.accept(healthCheckupVisitor);
zoo.accept(informationDisplayVisitor);
}
}
6 典型應用場景
訪問者模式允許你在不修改現有對象結構的情況下,定義新操作並將其應用於這些對象。以下是一些典型的訪問者模式應用場景:
-
數據結構與操作分離。當你有一個複雜的數據結構,其中包含多種不同類型的對象,並且希望對這些對象執行各種操作,但不希望將操作的代碼放在這些對象中時,訪問者模式可以幫助你將操作與數據結構分離開來。
-
數據結構穩定但操作頻繁變化。如果數據結構相對穩定,但需要經常添加新的操作或修改現有操作,使用訪問者模式可以輕鬆地添加新的訪問者類而不必修改數據結構類。
-
數據結構中對象類型多樣化。當你的數據結構中包含多個不同的對象類型,且你需要對每種類型執行不同的操作時,訪問者模式使得你可以輕鬆地擴展和管理這些操作。
-
數據結構具有複雜的嵌套結構。如果你的數據結構是一個複雜的嵌套結構,其中對象可以包含子對象,訪問者模式可以通過遞歸遍歷整個結構,使得操作更容易實施。
-
擴展性要求高。當你需要為系統提供高度可擴展性,以便能夠隨時添加新的操作和對象類型時,訪問者模式是一個有用的選擇,因為它使得添加新功能變得相對容易。
-
數據結構和操作分佈在不同的類庫中。如果數據結構和操作分別位於不同的類庫中,訪問者模式可以幫助你通過定義新的訪問者來擴展操作,而無需修改已有的類庫。
訪問者模式適用於需要對複雜對象結構進行多種不同操作的情況,同時又要保持數據結構的穩定性和可擴展性的需求。通過將操作封裝在訪問者對象中,它可以有效地解耦操作和數據結構,使得系統更加靈活和可維護。
7 優缺點
優點:
可擴展性。訪問者模式使得添加新的操作變得容易,無需修改已有的元素類。
分離關註點。訪問者模式將對象結構和操作分離,使得每個部分都可以獨立變化,提高了代碼的可維護性。
靈活性。可以定義多個不同的訪問者,每個訪問者執行不同的操作,從而實現靈活的行為擴展。
符合開閉原則。可以在不修改已有代碼的情況下添加新的訪問者和操作。
缺點:
增加複雜性。引入了訪問者和元素之間的額外層次,可能會增加代碼的複雜性。
不適用於小規模場景。在小規模場景下,使用訪問者模式可能會顯得繁瑣和過於複雜。
8 類似模式
與訪問者模式類似的模式包括以下幾種:
- 迭代器模式(Iterator Pattern):
迭代器模式和訪問者模式都用於處理集合或對象結構中的元素。它們都允許你遍歷集合中的元素,但它們的焦點不同。迭代器模式關註於提供一種訪問元素的方法,而訪問者模式關註於在元素上執行不同的操作。在迭代器模式中,通常有一個迭代器對象,它負責遍歷集合併提供對元素的訪問。而在訪問者模式中,訪問者對象負責定義要執行的操作,並遍歷對象結構來執行這些操作。
- 組合模式(Composite Pattern):
組合模式和訪問者模式通常一起使用,以便在對象結構中執行操作。組合模式用於表示樹形結構,而訪問者模式用於在樹形結構中執行操作。組合模式主要用於創建和管理樹形結構,它使得可以像對待單個對象一樣對待組合對象。訪問者模式則用於在樹形結構中執行不同的操作,將操作與對象分離。
- 觀察者模式(Observer Pattern):
觀察者模式和訪問者模式都屬於行為型設計模式,它們都涉及多個對象之間的交互。觀察者模式用於定義對象之間的一對多依賴關係,一個對象的狀態變化會通知所有依賴它的對象。訪問者模式用於在對象結構中執行不同的操作,與對象的狀態變化無關。
這些模式之間的聯繫在於它們都處理對象之間的關係,但它們的焦點和用途不同。訪問者模式主要用於在對象結構中執行不同的操作,而其他模式則更關註對象之間的交互、結構或組織。根據具體的問題和需求,你可以選擇使用適合的模式來改善設計和實現。
9 小結
訪問者模式是一種強大的設計模式,它可以使你輕鬆地添加新的操作,而不需要修改現有的元素類。通過將操作從元素類中分離出來,訪問者模式提高了代碼的可維護性和可擴展性。然而,它也可能會引入額外的複雜性,因此在小規模場景下使用時要謹慎。瞭解訪問者模式的結構和實現步驟,以及它的優缺點和典型應用場景,將有助於你在適當的情況下使用這一模式來改善代碼的設計和可維護性。