1. 什么是訪問者模式?
訪問者模式是一種行為設計模式,它允許你在不改變對象結構的前提下,定義新的操作。通過將操作封裝在訪問者對象中,訪問者模式使得你可以在不修改元素類的情況下,向元素類添加新的功能。
訪問者模式的核心思想是將操作與對象結構分離。通過引入一個訪問者對象,允許你在不修改對象結構的情況下,定義新的操作。這樣可以提高系統的靈活性和可擴展性。
訪問者模式通常包含以下幾個組成部分:
- 訪問者接口(Visitor Interface):定義訪問者的接口,通常包含對每個元素類的訪問方法。
- 具體訪問者(Concrete Visitor):實現訪問者接口,定義對每個元素類的具體操作。
- 元素接口(Element Interface):定義接受訪問者的接口,通常包含一個接受訪問者的方法。
- 具體元素(Concrete Element):實現元素接口,定義具體的元素類。
訪問者模式在軟件設計中具有多種優點:
- 分離操作與對象結構:通過將操作封裝在訪問者中,訪問者模式使得操作與對象結構分離,增強了系統的靈活性。
- 易于擴展:可以通過添加新的訪問者來擴展系統的功能,而不需要修改現有的元素類。
- 集中操作:所有操作都集中在訪問者中,便于管理和維護。
# 訪問者接口
class DiscountVisitor:def visit_book(self, book):passdef visit_electronic(self, electronic):pass# 具體訪問者
class PercentageDiscount(DiscountVisitor):def visit_book(self, book):return book.price * 0.9 # 書籍享受10%的折扣def visit_electronic(self, electronic):return electronic.price * 0.85 # 電子產品享受15%的折扣# 元素接口
class Item:def accept(self, visitor):pass# 具體元素
class Book(Item):def __init__(self, price):self.price = pricedef accept(self, visitor):return visitor.visit_book(self) # 接受訪問者class Electronic(Item):def __init__(self, price):self.price = pricedef accept(self, visitor):return visitor.visit_electronic(self) # 接受訪問者# 客戶端代碼
if __name__ == "__main__":items = [Book(100), Electronic(200)] # 創建購物車中的商品discount_visitor = PercentageDiscount() # 創建折扣訪問者for item in items:discounted_price = item.accept(discount_visitor) # 計算折扣后的價格print(f"Discounted price: {discounted_price}")
- 訪問者接口:
DiscountVisitor
類定義了訪問者的接口,包含對每個元素類的訪問方法(visit_book
和visit_electronic
)。 - 具體訪問者:
PercentageDiscount
類實現了訪問者接口,定義了對每個元素類的具體操作(計算折扣后的價格)。- 在
visit_book
方法中,書籍享受10%的折扣;在visit_electronic
方法中,電子產品享受15%的折扣。
- 元素接口:
Item
類定義了接受訪問者的接口,包含一個accept
方法。 - 具體元素:
Book
和Electronic
類實現了元素接口,定義具體的商品類,并實現accept
方法,接受訪問者。
- 客戶端代碼:
- 在客戶端代碼中,創建購物車中的商品和折扣訪問者,并通過調用
accept
方法來計算折扣后的價格。
- 在客戶端代碼中,創建購物車中的商品和折扣訪問者,并通過調用
2. 示例1:寵物店中的訪問者模式
- 訪問者接口(Visitor Interface):定義訪問者的接口,通常包含對每個寵物類的訪問方法。
- 具體訪問者(Concrete Visitor):實現訪問者接口,定義對每個寵物類的具體操作(如計算數量、平均體重和最大年齡)。
- 元素接口(Element Interface):定義接受訪問者的接口,通常包含一個接受訪問者的方法。
- 具體元素(Concrete Element):實現元素接口,定義具體的寵物類(如貓和狗)。
# 訪問者接口
class PetVisitor:def visit_cat(self, cat):passdef visit_dog(self, dog):pass# 具體訪問者:數量統計
class CountVisitor(PetVisitor):def __init__(self):self.cat_count = {'male': 0, 'female': 0}self.dog_count = {'male': 0, 'female': 0}def visit_cat(self, cat):self.cat_count[cat.gender] += 1def visit_dog(self, dog):self.dog_count[dog.gender] += 1def report(self):print(f"Cat Count: {self.cat_count['male']} males, {self.cat_count['female']} females")print(f"Dog Count: {self.dog_count['male']} males, {self.dog_count['female']} females")# 具體訪問者:平均體重計算
class WeightVisitor(PetVisitor):def __init__(self):self.total_cat_weight = 0self.total_dog_weight = 0self.cat_count = 0self.dog_count = 0def visit_cat(self, cat):self.total_cat_weight += cat.weightself.cat_count += 1def visit_dog(self, dog):self.total_dog_weight += dog.weightself.dog_count += 1def report(self):avg_cat_weight = self.total_cat_weight / self.cat_count if self.cat_count > 0 else 0avg_dog_weight = self.total_dog_weight / self.dog_count if self.dog_count > 0 else 0print(f"Average Cat Weight: {avg_cat_weight:.2f} kg")print(f"Average Dog Weight: {avg_dog_weight:.2f} kg")# 具體訪問者:最大年齡查找
class AgeVisitor(PetVisitor):def __init__(self):self.max_cat_age = 0self.max_dog_age = 0def visit_cat(self, cat):if cat.age > self.max_cat_age:self.max_cat_age = cat.agedef visit_dog(self, dog):if dog.age > self.max_dog_age:self.max_dog_age = dog.agedef report(self):print(f"Oldest Cat Age: {self.max_cat_age} years")print(f"Oldest Dog Age: {self.max_dog_age} years")# 具體元素:貓
class Cat:def __init__(self, gender, weight, age):self.gender = gender # 'male' or 'female'self.weight = weight # 體重self.age = age # 年齡def accept(self, visitor):visitor.visit_cat(self) # 接受訪問者# 具體元素:狗
class Dog:def __init__(self, gender, weight, age):self.gender = gender # 'male' or 'female'self.weight = weight # 體重self.age = age # 年齡def accept(self, visitor):visitor.visit_dog(self) # 接受訪問者# 客戶端代碼
if __name__ == "__main__":pets = [Cat('male', 4.5, 3),Cat('female', 3.0, 2),Dog('male', 10.0, 5),Dog('female', 8.5, 4),Cat('male', 5.0, 6),Dog('female', 9.0, 7)]count_visitor = CountVisitor() # 創建數量統計訪問者weight_visitor = WeightVisitor() # 創建平均體重計算訪問者age_visitor = AgeVisitor() # 創建最大年齡查找訪問者# 統計數量、計算平均體重和查找最大年齡for pet in pets:pet.accept(count_visitor) # 統計數量pet.accept(weight_visitor) # 計算平均體重pet.accept(age_visitor) # 查找最大年齡# 輸出統計結果count_visitor.report()weight_visitor.report()age_visitor.report()
Cat Count: 2 males, 1 females
Dog Count: 1 males, 2 females
Average Cat Weight: 4.17 kg
Average Dog Weight: 9.17 kg
Oldest Cat Age: 6 years
Oldest Dog Age: 7 years
-
訪問者接口:
PetVisitor
類定義了訪問者的接口,包含對每個寵物類的訪問方法(visit_cat
和visit_dog
)。 -
具體訪問者:
CountVisitor
類實現了訪問者接口,負責統計寵物的數量(按性別分類)。WeightVisitor
類實現了訪問者接口,負責計算寵物的平均體重。AgeVisitor
類實現了訪問者接口,負責找出年齡最大的貓和狗。
-
具體元素:
Cat
和Dog
類實現了元素接口,定義具體的寵物類,并實現accept
方法,接受訪問者。
-
客戶端代碼:
- 在客戶端代碼中,創建寵物對象(貓和狗)并創建數量統計、平均體重計算和最大年齡查找的訪問者。
- 通過調用
accept
方法,分別統計數量、計算平均體重和查找最大年齡,并打印結果。