脈絡:應用程式正用訊息傳遞來傳送不同型別的資料,例如不同類型的文件。

位元組不足以說明一切#

從訊息系統的角度看,所有訊息都只是同一種訊息型別的實例,內容最終不過是一個位元組陣列。這種「一包位元組」的簡單結構,對訊息系統傳輸訊息而言夠具體了,對接收端處理內容而言卻遠遠不夠

接收端必須知道訊息內容的資料結構資料格式

  • 結構可能是字元陣列、位元組陣列、序列化物件、XML 文件……
  • 格式可能是那些位元組或字元的紀錄結構、序列化物件的類別、XML 文件的 DTD……

這些知識統稱為訊息的型別——也就是訊息內容的結構與格式。

接收端必須知道自己收的是什麼型別的訊息,否則就不知道怎麼處理。寄件端可能想送採購單、報價、查詢等不同物件,而接收端處理每一種的步驟都不同,它必須分得出哪個是哪個。若寄件端把這些全部經由同一個通道送過去,接收端就無從得知該如何逐一處理。

幾個不太理想的替代方案#

寄件端明明知道自己在送什麼型別,該怎麼把這件事告訴接收端?

  • 在訊息表頭放一個旗標(見 Format Indicator)——可行,但接收端就得寫一堆 case 判斷。
  • 把資料包成 Command Message,每種資料型別對應不同命令——但這等於在擅自指示接收端該拿資料怎麼辦,而訊息真正想做的只是把資料傳過去。

一個相同的老問題:集合#

一個與訊息傳遞完全無關、卻結構相同的問題出現在非陣列的集合上:集合可以是異質的(每項都能是任意物件型別),但實務上集合應該是同質的(每項都是同型別,也就是都實作同一個抽象類別或介面)。

同質集合有用得多,因為集合上的迭代器知道每一項會是什麼型別,於是能用該型別懂得的方法去操作它。

同樣的原則適用於訊息傳遞——在這個脈絡下,通道就像集合,接收端就像迭代器。雖然通道並不要求所有訊息同型別,但它們就該是同型別,接收端才知道自己收到的是什麼。

解法#

  • 寄件端知道資料是什麼型別,因此會挑選對應的通道送出。
  • 接收端知道資料是從哪個通道收到的,因此就知道它的型別

通道不夠用時#

如同 Message Channel 一章所述,通道便宜但不免費。應用程式可能需要傳輸許多不同的資料型別,多到無法為每一種都開一個通道。

此時多種資料型別可以共用單一通道,作法是對每種型別各用一個 Selective Consumer——這讓一條通道表現得像多條資料型別通道。

  • Datatype Channel 解釋的是「為什麼同一通道上所有訊息必須同格式」
  • Canonical Data Model 解釋的是「為什麼企業中所有通道上的所有訊息都該遵循一套統一的資料模型」

與 Message Dispatcher 的關係#

Message Dispatcher 除了提供並行的訊息消費之外,也能用來以「型別專屬」的方式處理一組通用訊息:每則訊息必須標明自己的型別,dispatcher 偵測型別後把它派送給對應的執行者。

此時通道上的訊息仍然都是同一型別——只是那是 dispatcher 所支援的、較通用的型別,而不是各執行者所需的、較具體的型別。

範例:股票交易與採購系統

股票交易#

在股票交易系統中,若「報價請求」與「交易請求」的格式不同,系統就該用各自獨立的 Datatype Channel 傳遞。同樣地,「地址變更公告」與「投資組合經理人變更公告」的格式若不同,每種公告也該有自己的通道。

採購系統#

回到前面的例子:寄件端想送三種不同型別的資料(採購單、報價、查詢),它就該用三個不同的通道。送出時,寄件端必須為該項目挑選對應的 Datatype Channel;接收時,接收端因為知道自己是從哪個通道收到的,就知道它的型別