脈絡:應用程式正用訊息傳遞來傳送不同型別的資料,例如不同類型的文件。
位元組不足以說明一切#
從訊息系統的角度看,所有訊息都只是同一種訊息型別的實例,內容最終不過是一個位元組陣列。這種「一包位元組」的簡單結構,對訊息系統傳輸訊息而言夠具體了,對接收端處理內容而言卻遠遠不夠。
接收端必須知道訊息內容的資料結構與資料格式:
- 結構可能是字元陣列、位元組陣列、序列化物件、XML 文件……
- 格式可能是那些位元組或字元的紀錄結構、序列化物件的類別、XML 文件的 DTD……
這些知識統稱為訊息的型別——也就是訊息內容的結構與格式。
接收端必須知道自己收的是什麼型別的訊息,否則就不知道怎麼處理。寄件端可能想送採購單、報價、查詢等不同物件,而接收端處理每一種的步驟都不同,它必須分得出哪個是哪個。若寄件端把這些全部經由同一個通道送過去,接收端就無從得知該如何逐一處理。
幾個不太理想的替代方案#
寄件端明明知道自己在送什麼型別,該怎麼把這件事告訴接收端?
- 在訊息表頭放一個旗標(見 Format Indicator)——可行,但接收端就得寫一堆 case 判斷。
- 把資料包成 Command Message,每種資料型別對應不同命令——但這等於在擅自指示接收端該拿資料怎麼辦,而訊息真正想做的只是把資料傳過去。
一個相同的老問題:集合#
一個與訊息傳遞完全無關、卻結構相同的問題出現在非陣列的集合上:集合可以是異質的(每項都能是任意物件型別),但實務上集合應該是同質的(每項都是同型別,也就是都實作同一個抽象類別或介面)。
同質集合有用得多,因為集合上的迭代器知道每一項會是什麼型別,於是能用該型別懂得的方法去操作它。
同樣的原則適用於訊息傳遞——在這個脈絡下,通道就像集合,接收端就像迭代器。雖然通道並不要求所有訊息同型別,但它們就該是同型別,接收端才知道自己收到的是什麼。
解法#
- 寄件端知道資料是什麼型別,因此會挑選對應的通道送出。
- 接收端知道資料是從哪個通道收到的,因此就知道它的型別。
通道不夠用時#
如同 Message Channel 一章所述,通道便宜但不免費。應用程式可能需要傳輸許多不同的資料型別,多到無法為每一種都開一個通道。
此時多種資料型別可以共用單一通道,作法是對每種型別各用一個 Selective Consumer——這讓一條通道表現得像多條資料型別通道。
- Datatype Channel 解釋的是「為什麼同一通道上所有訊息必須同格式」
- Canonical Data Model 解釋的是「為什麼企業中所有通道上的所有訊息都該遵循一套統一的資料模型」
與 Message Dispatcher 的關係#
Message Dispatcher 除了提供並行的訊息消費之外,也能用來以「型別專屬」的方式處理一組通用訊息:每則訊息必須標明自己的型別,dispatcher 偵測型別後把它派送給對應的執行者。
此時通道上的訊息仍然都是同一型別——只是那是 dispatcher 所支援的、較通用的型別,而不是各執行者所需的、較具體的型別。