多分派或譯多重派發（multiple dispatch）或多方法（multimethod），是某些程式語言的一個特性，其中的函式或者方法，可以在執行時間（動態的）基於它的實際引數的型別，或在更一般的情況下於此之外的其他特性，來動態分派。這是對單分派多型的推廣， 那裡的函式或方法呼叫，基於在其上呼叫方法的物件的派生型別，而動態分派。多分派使用一個或多個實際引數的組合特徵，路由動態分派至實現函式或方法。 理解分派 軟體工程師通常把程式碼寫進程式碼塊中，程式碼塊通常稱作過程、函式、方法。程式碼透過被呼叫來執行，呼叫時將控制權傳入函式中，當函式執行完成後將控制權返回給呼叫者。 函式名通常用來描述函式的目的。有時會將多個函式起同樣的名稱。比如同名函式在邏輯上處理相同的任務，但是操作在不同型別的輸入值上。在這種情況下，無法僅僅透過函式名，來判斷目的碼塊。那麼，函式的實際引數的個數和型別，也就被用來判斷。 通常，單分派面嚮物件語言，在呼叫一個方法時，方法引數中一個引數會被特殊對待，並用來決定哪一個方法（如果有多個同名方法）會被呼叫。在許多語言中，這個特殊的引數是在語法上指明的，許多程式語言在呼叫方法時，把特殊引數放在小圓點之前。例如 specialmethod other arguments here，這樣 lionsound 將會發出獅吼，同時 sparrowsound 只會吱吱地叫。一般來說，對於面向物件的程式語言，這個小圓點之前的引數（上例中的 lion 和 sparrow）被稱為接收者。 相反，在實現了多分派的語言中，被呼叫的函式，即是那些引數個數一樣多，並且型別也匹配的呼叫。在呼叫中並沒有特殊引數，來決定那個方法被呼叫。也就是說，所有引數的執行時型別都參與分派。CLOS 是早期和著名的多分派語言。 資料型別 對於編譯時間可以區分資料型別的程式語言，在（alternative）函式中進行選擇，可以發生在編譯時間，建立交替函式用於編譯時間選擇的活動，通常被叫做函式過載。 在有些程式語言中，這種資料型別的識別，可以被延後至執行時間。交替函式的選擇發生在執行時間，並依據動態確定的函式實際引數的型別。以這種方式選擇交替實現的函式，通常被稱為多方法。 例子 可以透過例子更加清晰的區分多分派和單一分派。假想一個遊戲，它有兩種（使用者可見的）物體：飛船和小行星。當兩個物體要相撞的時候，程式需要依據什麼物體要相撞而做不同的事情。 具有內建多分派的語言 Common Lisp 在具有多分派的 Common Lisp 語言中，可以在 Common Lisp 物件系統中如下這樣實現： defgeneric collide x y defclass asteroid defclass spaceship defmethod collidewith x asteroid y asteroid deal with asteroid hitting asteroid defmethod collidewith x asteroid y spaceship deal with asteroid hitting spaceship defmethod collidewith x spaceship y asteroid deal with spaceship hitting asteroid defmethod collidewith x spaceship y spaceship deal with spaceship hitting spaceship 並且對其他方法也是類似的。沒有使用顯式測試和 動態轉換。 由於多分派的存在，方法要定義在類中幷包含在物件中的傳統想法，變得不再吸引人了，上述每個 collidewith 方法，都附屬於兩個不同的類而非一個類。因此方法呼叫的特殊語法，一般會消失，從而方法呼叫看起來完全就像正常的函式呼叫，並且方法被組織入泛化函式而非類中。 Julia Julia 有內建的多分派，並且它是語言設計的中心。Julia 版本的例子如下： collide_with xAsteroid yAsteroid deal with asteroid hitting asteroid collide_with xAsteroid ySpaceship deal with asteroid hitting spaceship collide_with xSpaceship yAsteroid deal with spaceship hitting asteroid collide_with xSpaceship ySpaceship deal with spaceship hitting spaceship C C 在版本 4（2010 年 4 月），使用關鍵字 dynamic，介入了對動態多方法的支援。下面的例子展示多方法協同於在版本 8（2019 年 9 月）中介入的 switch 表示式。像很多其他靜態型別的語言語言一樣，C 還支援靜態方法過載，Microsoft 預期開發者在多數場景下會選用靜態型別超過動態型別。dynamic 關鍵字支援 COM 物件和動態型別的NET 語言的互操作。 class Program static void Main ConsoleWriteLine ColliderCollide new Asteroid 101 new Spaceship 300 ConsoleWriteLine ColliderCollide new Asteroid 10 new Spaceship 10 ConsoleWriteLine ColliderCollide new Spaceship 101 new Spaceship 10 static class Collider public static string Collide SpaceObject x SpaceObject y xSize 100 ySize 100 Big boom CollideWith x as dynamic y as dynamic private static string CollideWith Asteroid x Asteroid y aa private static string CollideWith Asteroid x Spaceship y as private static string CollideWith Spaceship x Asteroid y sa private static string CollideWith Spaceship x Spaceship y ss abstract class SpaceObject public SpaceObject int size Size size public int Size get class Asteroid SpaceObject public Asteroid int size base size class Spaceship SpaceObject public Spaceship int size base size 輸出： bigboom as ss Groovy Groovy 是通用的 Java 相容 互用的 JVM 語言，它對立於 Java，使用後期繫結 多分派。 Groovy implementation of C example above Late binding works the same when using nonstatic methods or compiling classmethods statically CompileStatic annotation class Program static void main String args println Collidercollide new Asteroid 101 new Spaceship 300 println Collidercollide new Asteroid 10 new Spaceship 10 println Collidercollide new Spaceship 101 new Spaceship 10 class Collider static String collide SpaceObject x SpaceObject y xsize 100 ysize 100 bigboom collideWith x y Dynamic dispatch to collideWith method private static String collideWith Asteroid x Asteroid y aa private static String collideWith Asteroid x Spaceship y as private static String collideWith Spaceship x Asteroid y sa private static String collideWith Spaceship x Spaceship y ss class SpaceObject int size SpaceObject int size thissize size InheritConstructors class Asteroid extends SpaceObject InheritConstructors class Spaceship extends SpaceObject 用多分派庫擴充套件的語言 在不於語言定義或語法層次支援多分派的語言中，可能經常使用庫擴充套件來增加多分派。 JavaScript JavaScript 和 TypeScript 不在語言語法層次上支援多方法，但可以透過庫來增加多分派。例如，使用 multimethod 包 arrowsmultimethod Multiple dispatch in JavaScriptTypeScript with configurable dispatch resolution by Maciej Cąderek，它提供了多分派、泛化函式的實現。JavaScript 的動態型別版本： import multi method from arrowsmultimethod class Asteroid class Spaceship const collideWith multi method Asteroid Asteroid x y deal with asteroid hitting asteroid method Asteroid Spaceship x y deal with asteroid hitting spaceship method Spaceship Asteroid x y deal with spaceship hitting asteroid method Spaceship Spaceship x y deal with spaceship hitting spaceship TypeScript 有對應的靜態型別版本。 Python 可以使用庫擴充套件來向 Python 增加多分派。例如，最早的模組 multimethodspymultimethodspy Multiple dispatch in Python with configurable dispatch resolution by David Mertz et al，它為 Python 提供了 CLOS 風格的多方法而不用變更語言的底層語法或關鍵字。在功能上，這非常類似於 CLOS 例子，但是語法是常規 Python 的。 Guido van Rossum 使用 Python 24 介入的修飾器（decorator），出品了多方法的具有簡化了的語法的一個簡單實現，他為此定義了 multimethod 修飾器。 multipledispatch 採用的形式與之一致。 模組 multimethod，採用了修飾器和 Python 35 介入的型別提示實現多方法： from multimethod import multimethod class Asteroid pass class Spaceship pass multimethod def collide_with x Asteroid y Asteroid deal with asteroid hitting asteroid print asteroid hitting asteroid multimethod def collide_with x Asteroid y Spaceship deal with asteroid hitting spaceship print asteroid hitting spaceship multimethod def collide_with x Spaceship y Asteroid deal with spaceship hitting asteroid print spaceship hitting asteroid multimethod def collide_with x Spaceship y Spaceship deal with spaceship hitting spaceship print spaceship hitting spaceship a Asteroid b Spaceship collide_with a b asteroid hitting spaceship 此外，還有 PEAKRules 包提供語法類似上述例子的多分派，它後來被替代為 PyProtocols。Reg 庫也支援多分派和謂詞分派。 C C 語言使用 C Object System 庫，可以支援類似於 CLOS 的動態分派。它是完全可擴充套件的並且方法不需要任何的手工處理。動態訊息（方法）透過 COS 分派器來分派，它比 ObjectiveC 更快。下面是使用 COS 的例子： include stdioh include cosObjecth include cosgenobjecth 類 defclass Asteroid 資料成員 endclass defclass Spaceship 資料成員 endclass 泛化函式 defgeneric _Bool collide_with _1 _2 多方法 defmethod _Bool collide_with Asteroid Asteroid deal with asteroid hitting asteroid endmethod defmethod _Bool collide_with Asteroid Spaceship deal with asteroid hitting spaceship endmethod defmethod _Bool collide_with Spaceship Asteroid deal with spaceship hitting asteroid endmethod defmethod _Bool collide_with Spaceship Spaceship deal with spaceship hitting spaceship endmethod 用例 int main int argc char argv OBJ a gnew Asteroid OBJ s gnew Spaceship printf aa dn collide_with a a printf as dn collide_with a s printf dn collide_with s a printf dn collide_with s s grelease a grelease s 程式語言支援 主範型 Julia 支援通用的多方法 Clojure Common Lisp（透過 Common Lisp 物件系統） Dylan Groovy Nim，在 v020 之後泛化方法被廢止，使用多方法需要加編譯指令 Raku R VBNet，通過後期繫結，還透過Net DLR Wolfram 語言，透過符號模式匹配 透過擴充套件 任何NET 語言（透過庫 MultiMethodsNET） C（透過庫 C Object System） C（透過庫 multimethodsharp） C（透過庫 yomm2 和 multimethods） D（透過庫 openmethodsopenmethods） Factor（透過標準 multimethods 詞彙表 Java（使用擴充套件 MultiJava） JavaScript（透過包 arrowsmultimethod） Perl（透過模組 ClassMultimethods） Python（模組 multimethod、multipledispatch 或 Reg 庫） Racket（透過庫 multimethodlib） Ruby（透過 Multiple Dispatch 庫、Multimethod 包和 VlxMultimethods 包） Scheme（透過 TinyCLOS） TypeScript（透過包 arrowsmultimethod） 模擬多分派 C C 語言沒有動態分派，也可以不使用 C Object System 庫，而以某種形式手工實現。動態分派經常使用 enum 來標識一個物件的子型別，然後可透過在函式指標中查詢這個值來完成。C 語言模擬多方法的簡單例子： typedef void CollisionCasevoid void collision_AA void handle AsteroidAsteroid collision void collision_AS void handle AsteroidSpaceship collision void collision_SA void handle SpaceshipAsteroid collision void collision_SS void handle SpaceshipSpaceship collision typedef enum THING_ASTEROID 0 THING_SPACESHIP THING_COUNT not a type of thing itself instead used to find number of things Thing CollisionCase collisionCases THING_COUNTTHING_COUNT collision_AA collision_AS collision_SA collision_SS void collide Thing a Thing b collisionCases ab int main void collide THING_SPACESHIP THING_ASTEROID Java 在只有單一分派的語言比如 Java 中，多分派可以用多層單一分派來模擬： interface Collideable void collideWith final Collideable other These methods would need different names in a language without method overloading void collideWith final Asteroid asteroid void collideWith final Spaceship spaceship class Asteroid implements Collideable public void collideWith final Collideable other Call collideWith on the other object othercollideWith this public void collideWith final Asteroid asteroid Handle AsteroidAsteroid collision public void collideWith final Spaceship spaceship Handle AsteroidSpaceship collision class Spaceship implements Collideable public void collideWith final Collideable other Call collideWith on the other object othercollideWith this public void collideWith final Asteroid asteroid Handle SpaceshipAsteroid collision public void collideWith final Spaceship spaceship Handle SpaceshipSpaceship collision 執行時間 instanceof 檢查可以在一個或兩個層次上使用。 程式碼示例 引用 外部連結 Category 方法 電腦科學 Category 多型