以下文字源自我對源代碼的理解,如有不同意見,歡迎留言討論或發郵件(
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 完全有理由放在基類中,以派生類的形式開放此接口可能出於工程穩健性的角度考慮。
作為觀察者模式的實現,修改成員變量是一件非常慎重的事,僅在派生類中提供這一功能有兩點好處。一方面,整個系統通過派生類擁有了這一功能,可以在必要時啟用;另一方面,由於基類中沒有這一接口,特殊情況下要啟用此功能需要額外編寫轉化代碼,此功能在最大程度上被限制住了,起到了風險隔離的作用。
