面向对象设计的一个有缺陷的缓存机制

来源:互联网 发布:客多宝宠物店软件下载 编辑:程序博客网 时间:2024/05/02 00:56

        虽然这个标题有点拗口,但是它是我最近在项目中碰到的一次由最初的错误设计导致的重大bug。这类架构层面的设计失误,从一开始就埋下了隐患,后续随着开发小组的变动和软件模块的增加,非常难以跟踪,此外,一当软件编码完成,再有架构层面的变动,是非常耗时耗力的。故此,我将它复原出来,以免再犯同类错误。


一、最初的设计

1,总体架构

        最开始我们小组要开发一款“频谱仪”的控制软件,它的架构图如下:


如上图所示,它的大致架构是:

1)BL层以类的形式被GUI层调用;

2)BL层包含多个DLL模块,其中,Hardware(硬件)的接口以pure-c API的形式在BL层调用,其他模块以类的形式包含在BL层。


2,工作流程

        工作流程主要在BL层实现,它大致分为4个步骤,反复循环。


    如上图所示,BL层反复进行步骤“1 -> 4”的操作。其中步骤1中所谓的“设置硬件参数”,就是调用“Hardware API”中的1、2、3...等接口。


3,缓存机制

        对硬件的操作往往都是比较耗时的,假定步骤1中需要设置10个参数,每个参数对应一个API,每个API的调用响应时间为10ms,那么步骤1总耗时为100ms。

    经过观察,我们发现:

1)在前一次循环和后一次循环中,步骤1中的10个参数,大部分都是相同的;

2)硬件的10个参数是独立,并且会记住上一次的状态。

        基于以上事实,我们想到了用缓存参数的方法来减少对硬件接口的调用,从而提高控制软件的效率。

        这个缓存机制的大体思想是:

1)在BL层(它是一个类),设计10个类的成员变量,对应那10个硬件参数。

2)在步骤1中,BL层从GUI获得待设置的硬件参数的值时,先与对应的成员变量比较,如果相等,则不再调用对应的硬件接口。

        这个缓存机制的实现交给了B同事。他实现之后,测试OK。


二、新的需求

    最近项目提出了新的需求,需要BL层能够并发执行多个任务。架构变动如下:



如上图所示,在程序中同时运行了4个BL层的对象。


三、问题分析

        原本以为这个需求的对程序BL层无需改动,仅仅是在GUI层由原来new一个对象,变成new四个对象。窃以为,从一开始使用这种面向对象的设计,能够完美的解决多线程编程时遇到的“不可重入”问题。但是,在实际测试中发现:一当有两个及以上的BL对象同时运行,则获取的结果就出错。

    经过几天的试验和分析,终于找出了问题之所在:缓存机制。

    当把缓存机制去掉,问题解决。但是细细一想,问题是这么引入的:

1)对象化不完全!在整个程序设计中,其他模块都是对象化的,但是“Hardware API”不是。

2)同时运行两个个BL对象时,假定为A和B,A在前次循环和后次循环,看到它某个的成员变量并未改变,所以不重新设置硬件;而与此同时,B改变了那个硬件参数,但A并不知道。A和B是独立对象,但它们共用一个“Hardware API”。


四,解决方案

    找到问题点后,解决的办法有多种:

1)将所有待缓存的参数对应的成员变量设计为static;

2)判断是否某个参数是否改变时,实时从“Hardware API”中获取值,而不是用类的成员变量作为参考值。






0 0
原创粉丝点击