赵昶宇
(天津津航计算技术研究所,天津300308)
导致软件开发复杂化的因素有很多,比如越来越高的软件安全性和可靠性要求,其中最关键的因素是问题领域本身。为了降低软件复杂度,必须首先建立一个好的领域模型。该模型必须抓住领域的实质内容,并提供支持给相关软件开发人员。
为了降低软件耦合程度,简化软件设计,在软件的研制流程中,基于领域驱动的建模需要相关领域专家和软件开发人员结合领域专家的专业知识和软件开发人员的专业技能,建立准确柔性的领域模型,以更好响应需求变更,并缩短软件开发周期。对软件开发团队来说,多轮软件重构将会建立准确的深层领域模型,不仅能够极大地提高软件的复用率,并且能够在保证软件质量的前提下提高软件开发团队的研制能力,使软件具有较好的可扩展性。
近年来,基于领域驱动的设计思想已成为面向对象设计领域的新思潮。领域驱动的核心思想是通过消化大量知识,最终建立一个具备深层次领域知识和关键概念的模型。在领域驱动设计过程中,领域专家负责运用领域知识,软件开发人员负责运用专业技能对领域进行建模,最终建立领域深层含义的模型。该模型不但能够发现领域专家的关注点,还可以将其转变为有效可行的设计。在基于领域模型进行建模时,需关注以下几点:实现复杂巧妙的领域模型是需要花费很大心思和气力的;在领域专家和开发人员的密切合作下,只有通过不断重构才能构建深层次的领域模型;只有精通设计技巧才能实现并有效运用模型。
组合导航软件是应用于组合导航系统内的实时嵌入式软件,采集惯性器件信息,进行相应补偿,依据指令完成对准,利用相关基准信息进行组合导航,对外提供速度、位置、姿态角和加速度等导航控制参数。
采用标准的分层架构模式,给导航软件划分层次,如表1所示。
表1 导航软件的分层设计
在组合导航软件的每一层内,通过优化设计,其实高内聚于他的下层,而与它的上层具有松耦合性。领域层负责保存所有与领域相关的代码,该部分的代码与用户表示层、应用层以及基础设施层的代码是分开的。为了使领域模型具有丰富的含义和清晰的结构,在研究领域对象时需要重点关注如何表达领域模型,这样才能够获取到领域知识,更易于维护彼此独立的软件层。
组合导航软件各个层间的关系是松耦合的,且相邻两层之间是单向的依赖关系。上层元素通过调用下层元素的公共接口课直接使用或者操作下层的元素。而下层元素需要通过软件架构模式(Observers模式或回调模式)与上层元素进行通信,用于实现上下层之间的连接。如果连接方式能够保持领域层的独立性,并且在设计领域对象时不考虑可能与其交互的用户界面,则这种连接方式就是有效的。
基础设施层(如底层通讯类CCommunicate)不会发起对领域层的操作,它处于领域层之下,不包含其所服务的领域中的知识,这样应用层的元素就可以请求发送数据了,这样的解耦使程序的功能更加清晰。消息发送接口可以按不同通讯形式发送出去(RS232、RS422、网口、1553b等)。这种方式最主要的好处是简化了应用层,使其只专注于自己负责的事情:知道何时该发送信息,而不用关心如何发送。开发人员可以更加专注于核心领域问题的建模,这样可以大大提高效率和软件质量。
为提高系统精度,现在的组合导航系统中基本都包含卡尔曼滤波算法,以完成对准和组合功能。但由于系统特性差异,每个滤波器的实现有所不同。以往的做法中,每次研制新的导航软件时,卡尔曼滤波器都会因滤波参数不同、基准信息频率不同、滤波周期不同而将滤波算法重新设计实现,消耗资源大、更改时间长并且可靠性低。以下原因促使在滤波器算法设计中使用STRATEGY模式:①如果将组合和对准模块中分别加入各自需要的卡尔曼滤波算法,会使得程序很大并且难以维护,尤其当需要支持多种卡尔曼算法时,问题会更严重;②软件设计者往往希望在不同的时间使用不同的算法,但由于系统中软件均为嵌入式软件,空间资源有限,设计者不希望不使用的算法占用宝贵的空间;③如果卡尔曼滤波器成为程序中难以分割的成分(耦合度很高),增加新的卡尔曼滤波算法或改变现有算法将十分困难。
鉴于此,与深谙滤波算法的相关专家深入讨论,在分析之前实现的多个滤波算法的基础上,针对卡尔曼滤波器领域对象进行深入分析,发现每个滤波器的数据抽象部分基本一致,算法大体相同,仅滤波器初始化、计算系统矩阵、观测量获取等几个行为有区别,因此采用STRATEGY设计模式来实现这种算法的不同变体。
利用STRATEGY模式定义一系列的算法,把变化部分单独封装起来。该模式使得算法可独立于调用者而变化。将滤波器定义为kalman模板类,将各卡尔曼滤波器变化的行为部分抽象为基类(Mode),按照每个滤波器的特点定义子类。ⅠnitialValue、GetA、GetZ、GetH函数分别为参数初始化、计算系统矩阵、观测量获取等行为实现。用表示变化部分的mode类在滤波器对象构造时依据滤波特性进行模板匹配。
通过对滤波模型的多次重构得到了目前的模型,不仅可在研发过程中变更滤波需求,也能够满足新研项目对滤波器的需求,该滤波模型越来越接近柔性设计。利用该滤波模型的新研项目的滤波设计实现已经变得非常简单和可靠。
在组合导航系统中,要依据系统当前状态(如粗对准、精对准、组合导航)进行不同的行为动作,以往一般用大量嵌套switch/case语句分成互斥的几个区域,完成不同状态的规定动作。这样的代码不够清晰,而且难以修改和扩展。state模式提供了一个更好的方式来组织与特定状态相关的代码。决定状态转移的逻辑不在单个的if或switch语句中,而是分布在state子类中。将每一个状态转换和动作封装带一个类中,使与特定状态相关的行为局部化,并且使状态转换显式化。把着眼点从执行状态提高到整个对象的状态,这样使代码结构化并且意图更加清晰。
这一模式的关键思想是引入SysState的状态抽象类,表达系统的运行状态。SysState类为表示不同状态的子类声明了公共接口。SysState的子类实现与特定状态相关的行为。工作状态切换时需运行当前状态的GoOut和下一状态的ComeⅠn,完成状态的切换,切换时的一次性动作都可以放入相应函数。将在该状态下需要执行的动作放在Run函数。SysState类图如图1所示。
图1 SysState类图
有些与领域相关的操作从本质上讲是活动或动作,而不是事物。但由于建模一般针对对象,因此很多时候会把它们划归到对象范畴,一个常见的错误设计是没有为这类行为找到适合的对象,而是转为过程化的编程。如果勉强将一个操作放到不符合对象定义的对象中,会产生概念上的混淆,而且会变得很难理解或重构。此类抽象除了所掌握的操作之外在领域内没有其他意义。
若领域中某个重要的过程或转换操作不属于其他实体职责时,此时应在领域模型中增加一个SERVⅠCE操作。SERVⅠCE是一个独立的接口操作,它一般以活动命名,强调与其他对象之间的关系,它只用于定义能为客户做什么。在组合惯导系统中,在组合导航滤波算法中一般都会将接收到的卫星信息与惯性信息比较后进行有效性判断,这个操作依赖卫星对象和惯性解算对象的信息,判断的结果提供给组合导航滤波对象。将这个判断行为单独定义成类,从而实现了分离特定职责的效果,避免与其他对象耦合,有利于保持接口的简单性。
利用领域模型建模可以让软件开发人员表达丰富、准确具有柔性的软件功能需求,基于此功能需求实现的软件能够真正满足用户需求,是软件设计的关键所在。结合设计模式的使用有助于准确建立模型,提高了软件灵活性和可扩展性,大大降低了升级和移植的复杂度,降低了项目开发的风险,在保证软件质量的前提下极大提升了软件的研发速度