設計模式的分類
我們都知道有 23 種設計模式,這 23 種設計模式可分為如下三類:
- 創建型模式(5 種):單例模式、工廠方法模式、抽象工廠模式、建造者模式、原型模式。
- 結構型模式(7 種):適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
- 行為型模式(11 種):策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。
設計模式系列文章傳送門
設計模式的 7 大原則
設計模式–單例模式【創建型模式】
設計模式–工廠方法模式【創建型模式】
設計模式–抽象工廠模式【創建型模式】
設計模式–建造者模式【創建型模式】
設計模式–原型模式【創建型模式】
設計模式–適配器模式【結構型模式】
設計模式–裝飾器模式【結構型模式】
設計模式–代理模式【結構型模式】
設計模式–外觀模式(門面模式)【結構型模式】
設計模式–橋接模式【結構型模式】
設計模式–組合模式【結構型模式】
設計模式–享元模式【結構型模式】
設計模式–策略模式【行為型模式】
設計模式–模板方法模式【行為型模式】
設計模式–觀察者模式【行為型模式】
設計模式–迭代器模式【行為型模式】
設計模式–責任鏈模式【行為型模式】
設計模式–命令模式【行為型模式】
設計模式–備忘錄模式【行為型模式】
設計模式–狀態模式【行為型模式】
什么是訪問者模式
訪問者模式(Visitor Pattern)是一種行為型設計模式,通過定義一個訪問者對象,實現對數據結構中各個元素進行訪問和處理,訪問者模式可以將數據結構與數據操作分離,使得在增加新的操作時,不需要修改現有的數據結構相關的類。
訪問者模式的組成部分
- 抽象元素:定義一個接收訪問者的接口,接口中定義了一個接受訪問者的方法。
- 具體元素:實現了抽象元素接口,是數據結構中具體的元素,用于接受具體的訪問并執行相應的操作。
- 抽象訪問者:定義了對數據結構中各個元素訪問的操作方法。
- 具體訪問者:實現了訪問者抽象訪問者接口中具體的操作實現,也就是具體的操作邏輯。
- 對象結構:是一個包含元素角色的容器,并且提供了遍歷元素集合的方法,使得訪問者可以訪問每一個元素,一般是常見的 List、Map 等集合類。
訪問者模式案例演示
訪問者模式模式在生活中其實是有很多場景的,比如我們開一家早餐店,其中粉、面、粥、包子是各種不同的餐食,顧客可以根據自己的喜好選擇餐食,這里的顧客就是訪問者,而不同的食物則可以看做是元素,根據顧客的選擇來提供不同的食物,下面我們使用代碼來演示這個場景。
Food(抽象元素)
Food 食物就是本案例中的抽象元素,定義了一個接受訪問者訪問的方法,代碼如下:
public interface Food {//接受訪問的方法void accept(Customer customer);}
Pink(具體元素)
Pink 粉就是具體食物,也是一種具體的元素,實現了抽象元素 Food 接口,并重寫了訪問方法,將自身傳遞給訪問者,并提供了一個制作粉的方法,代碼如下:
public class Pink implements Food {@Overridepublic void accept(Customer customer) {//將 粉 元素傳遞給訪問者customer.visit(this);}//制作粉public void makePink() {System.out.println("我是一份廣東炒粉...");}}
Noodle(具體元素)
Noodle 面也是具體食物,同樣是一種具體的元素,實現了抽象元素 Food 接口,并重寫了訪問方法,將自身傳遞給訪問者,并提供了一個制作面的方法,代碼如下:
public class Noodle implements Food {@Overridepublic void accept(Customer customer) {customer.visit(this);}//制作面public void makeNoodle() {System.out.println("我是一份重慶小面...");}}
Bun(具體元素)
Bun 包子也具體食物,也是一種具體的元素,實現了抽象元素 Food 接口,并重寫了訪問方法,將自身傳遞給訪問者,并提供了一個制作包子的方法,代碼如下:
public class Bun implements Food {@Overridepublic void accept(Customer customer) {customer.visit(this);}//制作包子public void makeBun() {System.out.println("我是一份上海小籠包...");}}
Customer(訪問者)
Customer 訪問者,在本案例中顧客就是一個訪問者,訪問者中定義了粉、面、包子的訪問方法,代碼如下:
public interface Customer {//粉void visit(Pink pink);//面void visit(Noodle noodle);//包子void visit(Bun bun);
}
SpecificCustomer(具體訪問者)
SpecificCustomer 是一個具體訪問者,重寫了 Customer 中的粉、面、包子的訪問方法,代碼如下:
public class SpecificCustomer implements Customer{@Overridepublic void visit(Pink pink) {System.out.println("后廚,小王要了一份廣東炒粉...安排起來");pink.makePink();}@Overridepublic void visit(Noodle noodle) {System.out.println("后廚,小李要了一份重慶小面...安排起來");noodle.makeNoodle();}@Overridepublic void visit(Bun bun) {System.out.println("后廚,小美要了一份上海小籠包...安排起來");bun.makeBun();}
}
FoodCollection(對象結構)
FoodCollection 就是本案例中的對象結構,FoodCollection 中有一個 List 容器,存儲了 Food 食物,并提供了添加食物和訪問食物的方法,代碼如下:
public class FoodCollection {List<Food> foodList = new ArrayList<>();public void addFood(Food food){foodList.add(food);}public void accept(Customer customer){for (Food food : foodList) {food.accept(customer);}}}
VisitorClient(客戶端代碼)
三位顧客分別要了不同的食物,代碼如下:
public class VisitorClient {public static void main(String[] args) {//對象結構FoodCollection foodCollection = new FoodCollection();//粉--元素Pink pink = new Pink();//面--元素Noodle noodle = new Noodle();//包子--元素Bun bun = new Bun();//添加到數據集合中foodCollection.addFood(pink);foodCollection.addFood(noodle);foodCollection.addFood(bun);//具體訪問者SpecificCustomer customer = new SpecificCustomer();//開始訪問foodCollection.accept(customer);}}
執行結果如下:
后廚,小王要了一份廣東炒粉...安排起來
我是一份廣東炒粉...
后廚,小李要了一份重慶小面...安排起來
我是一份重慶小面...
后廚,小美要了一份上海小籠包...安排起來
我是一份上海小籠包...
執行結果符合預期。
訪問者模式的優缺點
優點:
- 數據結構和對這些數據結構進行操作的算法(即訪問者)是進行了分離,使得數據結構的維護和操作更加容易,體現了解耦的思想。
- 符合單一只能原則,每個類的職責明確,使得代碼更加清晰、易于理解和維護,當出現問題時,能夠更容易地定位到問題所在的類,提高了代碼的可維護性。
- 代碼復用性較好,通過訪問者來定義所有數據結構的通用功能,在一定程度上提到了代碼的復用。
缺點:
- 增加新的數據結構困難,每增加一個新的元素,都需要修改訪問者代碼,增加相對應的操作,違反了開閉原則。
- 在有較多元素的場景的時候,訪問者類會比較復雜,大量的元素的操作會導致訪問者類變的異常復雜。
訪問者模式的使用場景
- 需要對一個復雜的數據結構進行操作,且這些操作可能需要根據不同的元素類型進行不同操作時,可以使用訪問者模式。
- 需要在不同的數據結構中執行類似的操作,但不希望在數據結構中添加新的方法時,可以使用訪問者模式。
總結:本篇分享了訪問者模式設計模式,感覺訪問者設計模式還是有一點復雜的感覺,它除了元素和訪問者之外還有一個對象結構的概念,我們使用餐廳有有不同餐食的場景演示了訪問者模式,希望可以幫助不太熟悉訪問者模式的朋友加深理解。
如有不正確的地方歡迎各位指出糾正。