設計模式解密(22)- 訪問者模式
前言:訪問者模式拆分
訪問者模式基礎篇 :http://www.cnblogs.com/JsonShare/p/7380772.html
訪問者模式擴充套件篇 - 分派的概念: http://www.cnblogs.com/JsonShare/p/7381705.html
1、分派的概念
變數被宣告時的型別叫做變數的靜態型別(Static Type),有些人又把靜態型別叫做明顯型別(Apparent Type);而變數所引用的物件的真實型別又叫做變數的實際型別(Actual Type)。比如:
Map map = null;
map = new HashMap();
宣告瞭一個變數map,它的靜態型別(也叫明顯型別)是Map,而它的實際型別是HashMap。
根據物件的型別而對方法進行的選擇,就是分派(Dispatch),分派(Dispatch)又分為兩種,即靜態分派和動態分派。
靜態分派(Static Dispatch)發生在編譯時期,分派根據靜態型別資訊發生。靜態分派對於我們來說並不陌生,方法過載就是靜態分派。
動態分派(Dynamic Dispatch)發生在執行時期,動態分派動態地置換掉某個方法。
靜態分派:Java通過方法過載支援靜態分派。
動態分派:Java通過方法的重寫支援動態分派。
2、動態分派
Java通過方法的重寫支援動態分派。
例項:
package com.designpattern.Visitor.expand.Dynamic; /** * 動態分派 * @author Json<<json1990@foxmail.com>> */ class Dog { public void excute(){ System.out.println("我是dog媽媽"); } } class DogBaby1 extends Dog { public void excute(){ System.out.println("我是dogbaby1"); } } class DogBaby2 extends Dog { public void excute(){ System.out.println("我是dogbaby2"); } } public class Client { public static void main(String[] args) { Dog baby1 = new DogBaby1(); baby1.excute(); Dog baby2 = new DogBaby2(); baby2.excute(); } }
變數baby1的靜態型別是Dog,而真實型別是DogBaby1。
excute()方法呼叫的是DogBaby1類的excute()方法,那麼上面列印的就是“我是dogbaby1”;
變數baby2的靜態型別是Dog,而真實型別是DogBaby2。
excute()方法呼叫的是DogBaby2類的excute()方法,那麼上面列印的就是“我是dogbaby2”;
所以,問題的核心就是Java編譯器在編譯時期並不總是知道哪些程式碼會被執行,因為編譯器僅僅知道物件的靜態型別,而不知道物件的真實型別;而方法的呼叫則是根據物件的真實型別,而不是靜態型別。
3、靜態分派
Java通過方法過載支援靜態分派。
例項:
package com.designpattern.Visitor.expand.Static; /** * 靜態分派 * @author Json<<json1990@foxmail.com>> */ class Dog { } class DogBaby1 extends Dog{ } class DogBaby2 extends Dog{ } class Execute { public void excute(Dog dog){ System.out.println("我是dog媽媽"); } public void excute(DogBaby1 baby1){ System.out.println("我是dogbaby1"); } public void excute(DogBaby2 baby2){ System.out.println("我是dogbaby2"); } } public class Client { public static void main(String[] args) { Dog dog = new Dog(); Dog baby1 = new DogBaby1(); Dog baby2 = new DogBaby2(); Execute exe = new Execute(); exe.excute(dog); exe.excute(baby1); exe.excute(baby2); } }
顯然,Execute類的excute()方法是由三個方法過載而成的。這三個方法分別接受狗(Dog)、狗baby1(DogBaby1)、狗baby2(DogBaby2)等型別的引數。
那麼在執行時,程式會列印出什麼結果呢?
我是dog媽媽
我是dog媽媽
我是dog媽媽
為什麼呢?三次對excute()方法的呼叫傳入的是不同的引數,分別是dog、baby1、baby2。它們雖然具有不同的真實型別,但是它們的靜態型別都是一樣的,均是Dog型別。
過載方法的分派是根據靜態型別進行的,這個分派過程在編譯時期就完成了。
4、雙(重)分派
Java是靜態多分派、動態單分派的語言。
Java不支援動態的雙分派。但是通過使用設計模式,也可以在Java語言裡實現動態的雙重分派。
首先,什麼是雙分派?還記得 設計模式解密(22)- 訪問者模式 中舉的例子嗎?
訪問者模式用到了一種雙分派的技術,所謂雙分派技術就是在選擇一個方法的時候,不僅僅要根據訊息接收者(receiver)的執行時區別(Run time type),還要根據引數的執行時區別。在訪問者模式中,客戶端將具體狀態當做引數傳遞給具體訪問者,這裡完成第一次分派,然後具體訪問者作為引數的“具體狀態”中的方法,同時也將自己this作為引數傳遞進去,這裡就完成了第二次分派。雙分派意味著得到的執行操作決定於請求的種類和接受者的型別。
雙分派的核心就是這個this物件。
說到這裡,我們已經明白雙分派是怎麼回事了,但是它有什麼效果呢?就是可以實現方法的動態繫結,我們可以對上面的程式進行修改。
程式碼:
package com.designpattern.Visitor.expand.doubleDispatch; /** * 雙重分派 * @author Json<<json1990@foxmail.com>> */ class Dog { public void accept(Execute exe){ exe.excute(this); } } class DogBaby1 extends Dog{ public void accept(Execute exe){ exe.excute(this); } } class DogBaby2 extends Dog{ public void accept(Execute exe){ exe.excute(this); } } class Execute { public void excute(Dog dog){ System.out.println("我是dog媽媽"); } public void excute(DogBaby1 baby1){ System.out.println("我是dogbaby1"); } public void excute(DogBaby2 baby2){ System.out.println("我是dogbaby2"); } } public class Client { public static void main(String[] args) { Dog dog = new Dog(); Dog baby1 = new DogBaby1(); Dog baby2 = new DogBaby2(); Execute exe = new Execute(); dog.accept(exe); baby1.accept(exe); baby2.accept(exe); } }
結果:
我是dog媽媽
我是dogbaby1
我是dogbaby2
從結果可以看出:雙分派實現動態繫結的本質,就是在過載方法委派的前面加上了繼承體系中覆蓋的環節,由於覆蓋是動態的,所以過載就是動態的了!!!
PS:原始碼地址 https://github.com/JsonShare/DesignPattern/tree/master
PS:原文地址 http://www.cnblogs.com/JsonShare/p/7381705.html
相關文章
- 設計模式(十六)——訪問者模式設計模式
- 極簡設計模式-訪問者模式設計模式
- 設計模式 - ASM 中的訪問者模式設計模式ASM
- 設計模式學習之訪問者模式設計模式
- C#設計模式之訪問者模式C#設計模式
- 【趣味設計模式系列】之【訪問者模式】設計模式
- 15.java設計模式之訪問者模式Java設計模式
- Android理解設計模式之組合模式、迭代器模式、訪問者模式Android設計模式
- 設計模式(二十三)訪問者設計模式
- Java進階篇設計模式之十 ---- 訪問者模式和中介者模式Java設計模式
- 設計模式學習-使用go實現訪問者模式設計模式Go
- 「補課」進行時:設計模式(18)——訪問者模式設計模式
- 軟體設計模式系列之二十五——訪問者模式設計模式
- 軟體設計模式學習(二十七)訪問者模式設計模式
- 訪問者模式模式
- 行為模式-訪問者模式模式
- C++設計模式 - 訪問器模式(Visitor)C++設計模式
- Java23種設計模式【22】----》觀察者模式(Observer)Java設計模式Server
- 【設計模式】詳解訪問者(Visitor)模式-有多段程式碼出沒設計模式
- 設計模式學習筆記(二十一)訪問者模式及其實現設計模式筆記
- 聊聊OOP中的設計原則以及訪問者模式OOP模式
- python-訪問者模式Python模式
- GoLang設計模式17 - 訪客模式Golang設計模式
- 設計模式----建造者模式設計模式
- 設計模式(建造者模式)設計模式
- 設計模式 | 建造者模式設計模式
- 設計模式 --建造者模式設計模式
- 設計模式-建造者模式設計模式
- 設計模式 —— 建造者模式設計模式
- 深入淺出訪問者模式模式
- DesignPattern_訪問者模式_19模式
- PHP設計模式-DAO (Data Access Objects) 資料訪問物件模式PHP設計模式Object物件
- 設計模式 —— 觀察者模式設計模式
- 設計模式-適配者模式設計模式
- 設計模式——裝飾者模式設計模式
- 設計模式(觀察者模式)設計模式
- java設計模式-建造者模式Java設計模式
- 設計模式----觀察者模式設計模式
- 設計模式-裝飾者模式設計模式