以下文字源自我對源代碼的理解,如有不同意見,歡迎留言討論或發郵件(
xuruilong100@163.com
)
QuantLib 金融計算——原理之 Quote、Handle 與觀察者模式
QuantLib 中的觀察者模式
QuantLib 的設計初衷是提供一個生產環境下的實時計算框架,而不是作為一個教學工具。生產環境中的計算任務通常面臨一個非常現實的訴求,即需要某種機制可以觸發自動計算,而設計模式中的觀察者模式通常可以用來實現這一功能。正是實時計算的要求,要保證所有的計算都在相同的估值日期發生,這也就是為什么作為單體模式實現的 Settings
中存在 evaluationDate
方法。
QuantLib 中的觀察者模式有兩個類合作實現,一個是 Observer
,另一個是 Observalbe
,兩個類扮演的角色不言自明。
Observer
和 Observalbe
是非常底層的基類,用戶最常打交道的其實是另外兩個類,一個是 SimpleQuote
,它是 Quote
的派生類(Quote
是 Observalbe
的派生類);另一個是類模板 Handle
,Handle
借助內部類 Link
同時扮演觀察者和被觀察對象的角色,也就是充當“傳令官”。
SimpleQuote
的實現很簡單,可以把它理解成為一個帶有通知功能的智能浮點數。
Handle
在構造具體實例的時候會注冊成為一個 SimpleQuote
對象的觀察者(以智能指針的形式存在),當 SimpleQuote
對象通過 setValue
重新設置數值的時候便會通知自己的觀察者,由於 Handle
傳令官的的角色定位,其他接受 Handle
作為構造函數參數的類緊接着會收到通知(因為這些類在接受 Handle
時也會注冊成為 Handle
的觀察者),而在這一步,某些計算會被觸發。所以,Handle
必須扮演雙重角色。
Handle
存在的意義
Quote
本身就能通知自己的觀察者,為何還要再經過 Handle
之手?
在 C++ 工程實踐中智能指針被廣泛應用,函數的接口通常以引用或智能指針的形式存在。如果僅僅傳遞一個 Quote
的智能指針,當指針在外部重新指向其他地址之后,通知觀察者的動作其實是無法被觸發的。因此,需要一個機制來管理指針自身的變化,這也就是 Handle
要完成的任務。確切的說,其實是 RelinkedHandle
的任務。這也就是為什么 QuantLib 大部分構造函數被設計成了接受 Handle
對象,而非 Quote
對象或智能指針。
Handle
與 RelinkedHandle
Handle
的架構層次只有兩層,派生類 RelinkedHandle
僅擴充了一個接口 linkTo
。RelinkedHandle
通過 linkTo
可以重置自身成為其他對象的觀察者。
單純從代碼的角度看,因為架構層次很淺,linkTo
完全有理由放在基類中,以派生類的形式開放此接口可能出於工程穩健性的角度考慮。
作為觀察者模式的實現,修改成員變量是一件非常慎重的事,僅在派生類中提供這一功能有兩點好處。一方面,整個系統通過派生類擁有了這一功能,可以在必要時啟用;另一方面,由於基類中沒有這一接口,特殊情況下要啟用此功能需要額外編寫轉化代碼,此功能在最大程度上被限制住了,起到了風險隔離的作用。