文章

QuantLib 金融计算——原理之 Quote、Handle 与观察者模式

介绍 QuantLib 中观察者模式的实现,即 Quote 和 Handle 这两个类。

以下文字源自我对源代码的理解,如有不同意见,欢迎留言讨论或发邮件(xuruilong100@163.com

QuantLib 金融计算——原理之 Quote、Handle 与观察者模式

QuantLib 中的观察者模式

QuantLib 的设计初衷是提供一个生产环境下的实时计算框架,而不是作为一个教学工具。生产环境中的计算任务通常面临一个非常现实的诉求,即需要某种机制可以触发自动计算,而设计模式中的观察者模式通常可以用来实现这一功能。正是实时计算的要求,要保证所有的计算都在相同的估值日期发生,这也就是为什么作为单体模式实现的 Settings 中存在 evaluationDate 方法。

QuantLib 中的观察者模式有两个类合作实现,一个是 Observer,另一个是 Observalbe,两个类扮演的角色不言自明。

ObserverObservalbe 是非常底层的基类,用户最常打交道的其实是另外两个类,一个是 SimpleQuote,它是 Quote 的派生类(QuoteObservalbe 的派生类);另一个是类模板 HandleHandle 借助内部类 Link 同时扮演观察者和被观察对象的角色,也就是充当“传令官”。

SimpleQuote 的实现很简单,可以把它理解成为一个带有通知功能的智能浮点数。

Handle 在构造具体实例的时候会注册成为一个 SimpleQuote 对象的观察者(以智能指针的形式存在),当 SimpleQuote 对象通过 setValue 重新设置数值的时候便会通知自己的观察者,由于 Handle 传令官的的角色定位,其他接受 Handle 作为构造函数参数的类紧接着会收到通知(因为这些类在接受 Handle 时也会注册成为 Handle 的观察者),而在这一步,某些计算会被触发。所以,Handle 必须扮演双重角色。

Handle 存在的意义

Quote 本身就能通知自己的观察者,为何还要再经过 Handle 之手?

在 C++ 工程实践中智能指针被广泛应用,函数的接口通常以引用或智能指针的形式存在。如果仅仅传递一个 Quote 的智能指针,当指针在外部重新指向其他地址之后,通知观察者的动作其实是无法被触发的。因此,需要一个机制来管理指针自身的变化,这也就是 Handle 要完成的任务。确切的说,其实是 RelinkedHandle 的任务。这也就是为什么 QuantLib 大部分构造函数被设计成了接受 Handle 对象,而非 Quote 对象或智能指针。

HandleRelinkedHandle

Handle 的架构层次只有两层,派生类 RelinkedHandle 仅扩充了一个接口 linkToRelinkedHandle 通过 linkTo 可以重置自身成为其他对象的观察者。

单纯从代码的角度看,因为架构层次很浅,linkTo 完全有理由放在基类中,以派生类的形式开放此接口可能出于工程稳健性的角度考虑。

作为观察者模式的实现,修改成员变量是一件非常慎重的事,仅在派生类中提供这一功能有两点好处。一方面,整个系统通过派生类拥有了这一功能,可以在必要时启用;另一方面,由于基类中没有这一接口,特殊情况下要启用此功能需要额外编写转化代码,此功能在最大程度上被限制住了,起到了风险隔离的作用。

本文由作者按照 CC BY 4.0 进行授权