15 June 2012

这篇文章属于《恰同学少年》系列,写于2012年。

“青囊”是一款Android上的用药提醒软件,本文对其进行面向对象的分析和设计。面向对象方法从早期注重编程发展成为一套完整的软件工程理论与技术,它使得在软件的分析、设计、实现、测试等阶段均采用一致的概念和指导思想,彼此能够紧密的衔接。除了本文涉及的分析和设计,青囊的开发也采用了面向对象语言(Java)和思想。

接下来的内容首先对青囊软件的需求和功能做总体上的说明,然后采用统一建模语言(UML)分别建立系统分析模型和设计模型并详细介绍,最后进行总结。

背景和需求说明

该软件系统开发的背景是手机App的日益流行。目前基于Android系统的智能手机越来越多,在手机上以app的形式提供各种功能,既大大方便了用户,也创造了新的商机。青囊系统旨在为病人(或病人家属)管理和服用药品提供便利。该系统包括客户端和服务器两部分。服务器端存储有大量电子化的药品说明书等信息,可以根据药品条形码查询获取;并且有用户数据库,以提供对用户数据管理的支持。客户端是一个Android手机上用的app,方便用户随身携带,随时使用。详细需求和功能说明如下:

手机使用者能够在客户端进行多用户管理。“多用户”指的是在青囊app中有一个用户列表,可以增加新用户或删除已有用户。设计多用户的目的在于app使用者除了自己用药,可能需要关心家人或亲属的用药。

对每一个用户,维护一个药品列表,即该用户应服用的药品。对药品列表可以进行添加、删除等操作。

添加药品需要支持条形码扫描和自动药品信息获取。青囊使用者可以直接扫描药品条形码,然后客户端从服务器获取条形码对应的药品说明书信息。除扫描外,也支持条码的输入。

对每一个添加的药品,客户端可以根据说明书内容自动为该药品生成一个闹钟提醒,在应服药的时刻提醒用户。用户可以根据实际情况修改这个自动生成的提醒。

对于客户端添加和删除用户、添加和删除药品的操作,需要通知服务器端进行记录。

面向对象的分析模型

这部分对青囊系统进行分析。采用面向对象的分析方法,系统的OOA模型包括需求模型、基本模型、辅助模型三部分,都可采用UML中的图来表示。需求模型即用况图,描述用户需求;基本模型即类图,描绘系统中的对象、对象的内部特征及相互关系;辅助模型是以其他图的形式对基本模型起辅助说明作用。下面分别介绍。

需求模型

根据前面对系统功能和需求的说明,可画出系统的用况图如图1所示。

图1:青囊系统用况图

图中的各个用况对应系统的各个需求。“管理用户(Manage Users)”是对用户列表的管理,参与者为手机app的使用者。“添加用户(Add User)”和“删除用户(Delete User)”都是用户管理的扩展。“管理药品(Manage Medicines)”与“管理用户”两个用况类似,仅针对的对象不同。

对于“删除用户”这个用况,它还包括(include)了“删除药品”。对应的实际需求为:如果在删除用户的时候,该用户拥有的药品不再有用,也将其删除(实际实现时需要提示一下用户)。

对于用户和药品的添加和删除这几个用况,由于它们除了在客户端由用户操作,还应该与服务器通信,告知服务器,因此他们的参与者包括服务器(Server)。

“添加药品”这个用况,其内部涉及条形码扫描和从服务器取药品的电子说明书,还包括扫描失败时转为手动输入等。后面会在辅助模型中以活动图的方式进一步说明。

基本模型

以类图表示的系统基本模型如图2所示。

图2:青囊系统类图

为了清晰,在类图中将类组织为了几个区域(这也对应辅助模型里的包图)。另外,由于Android系统(及其上的开发)本身就是处处基于面向对象的,所以SDK里面已经提供了大量一般类,青囊系统设计时除自身数据对应的类之外大多为继承而来。

Activity类是Android系统对每个交互单元的抽象。它提供OnCreate(), OnDestroy()等一般的函数,用于定义交互开始和结束等阶段时的操作。ListActivity是对Activity的特殊化,适合于对列表操作的情况,除了继承一般的OnCreate()等函数,还包括自己该种交互独有的OnListClicked()函数,即点击列表项时的操作;数据成员也增加了列表对应的属性。青囊系统中的用户管理和药品管理都属于列表管理,因此对应的类都继承ListActivity。类似的,BarcodeScanActivity是Activity的另一种特殊化,而MedicineAddActivity则进一步继承了BarcodeScanActivity。这部分类图集中体现了面向对象中类的一般-特殊关系。

右侧是从青囊的问题域中提取出的与应用逻辑相关的类。QNUser是对一个用户的抽象。每个用户有id、name等属性,可以进行添加、删除药品等操作。类似的,QNMedicine、QNReminder是对药品和提醒的抽象。每个用户可以同时服用多个药品,因此QNUser与QNMedicine是一对多的关联关系。图中用聚合来反映二者之间的关系(聚合是关联的一种特殊形式,尤其从实现上来说;二者的差别只是语义上的,聚合有更多的整体-部分含义)。由于每个药品都有一个服用提醒(在药品添加时就自动根据药品说明书生成一个提醒,即QNMedicine的对象和QNReminder的对象生命周期相同),我们将QNReminder作为QNMedicine的一部分设计为组合关系,以体现这种紧密、固定的关系。

List是一个借口,提供了要求实现的一系列操作,如add、remove,size等,它是没有属性的。ArrayList类以数组列表的形式实现了该接口,其他类也可以实现该接口(如Java中的LinkedList类)。HashMao也是Map接口的一个实现。图中将这些工具类放在java.util这一部分,它们也是青囊系统其他类要用到的。

辅助模型

辅助模型是对需求模型和基本模型的补充。UML中的辅助模型图包括包图、顺序图、活动图、状态机图、构件图、部署图、组合结构图、定时图,等等。在实际设计中可以根据需要采取其中的一种或几种。我们在前面提到添加药品这个用况相对比较复杂,因此这里给出其对应的活动图,以描述这一系统行为的具体过程。见图3。在类图中,我们已经把各个类按照它们所属的方面做了划分,事实上可以用包图来完成这种模型元素的组织,以形成较大粒度的系统单位。图4是青囊系统的包图(由于建模工具不支持在包图中画类,所以只表示出了各个包及其关系;各个包中所含的类参见图2类图中的区域划分)。

图3:添加药品的活动图

图4:青囊系统包图

模型规约

模型规约用于对系统模型进行详细说明,给出更完整、精确的模型信息。对模型规约的描述,可以采用自然语言或形式语言,或二者混合。模型规约的组织形式可以是分离与模型图,也可以混合在模型图中。如在图2所示的类图中,蓝色的评论文字就属于模型规约。本系统比较简单,不再更多引入模型规约。

面向对象的设计模型

面向对象的设计(OOD)是在OOA的基础上,结合具体的软硬件条件进行系统设计,以产生一个能够在特定平台上实现的OOD模型。面向对象的设计模型框架包括以下几个部分:问题域部分,人机交互部分,控制驱动部分和数据接口部分。本文主要对其中的问题域部分和数据接口部分的一些内容进行说明。

问题域部分的设计

问题域部分的设计基于来自问题域的对象,是在OOA模型基础上,按照具体的实现条件进行必要的修改、调整和细节补充而得到。

对于青囊系统,实现时主要是在Android平台上用Java语言编写,结合Java语言中的通信方式和手机平台的流量限制,对QNNetworker这一个类进行了进一步细化,并增加了需要的新类。如图5所示。

图5:QNNetworker结合实现条件的细化

因为手机app上的通信要考虑到流量的问题,所以应选取传送字节少的通信方式。因此设计为使用JSON格式作为数据的组织形式,而且自己开socket进行通信,不采用标准的HTTP。这样在QNNetworke中就要增加用于socket通信的主机、端口属性,以及JSON对象与字符串(字节流)之间的转换操作。JSONObject类是对Java语言中对JSON对象的抽象,它可以把各种数据类型封装进去。

其余的类也可根据需要进行调整和细化。OOA和OOD之间可以说也没有清晰的界限,所以OOA中已经定义清楚的类就可以在OOD中不再改动。

数据接口部分的设计

青囊系统的数据接口部分设计在服务器端和客户端是不一样的。在服务器端,存储的是药品、用户,以及用户和药品的关联信息。在客户端,需要存储的是其所维护的用户列表,药品列表和提醒等数据。

在手机端,我们采用文件的方式存储数据:使用Java的序列化机制,在程序退出时把所有的QNUser类的对象(包括与QNUser所关联的类的对象)序列化至磁盘数据文件,程序启动时再将其恢复。

在服务器端,考虑到数据库系统相比于文件系统的优势和实现上的方便性,决定采用数据库系统。主要是三个表,分别如下:

表1:药品表

字段 类型 备注
id varchar 条形码;主键
name varchar 名称
manual varchar 说明书


表2:用户表

字段 类型 备注
id int 递增id;主键
name varchar 用户名称


表3:用药信息记录表

字段 类型 备注
id int 递增id;主键
User_id varchar 外键
Medicine_id varchar 外键


上述三个表中,药品表是预先输入的电子化的药品信息,供客户端查询用。用户表和用药信息表则是由客户端的使用情况而更新。目前的设计尚未利用收集到的用药信息,但将来可能用于药品推送等的依据。

总结

本文是对用药提醒软件“青囊”进行的分析和设计。由于本软件是一个Android手机平台的应用,它的分析、设计、开发和维护都与传统的系统不太一样。例如,AndroidSDK已经提供了大量可以直接继承的一般类用于界面和交互;手机上的应用往往既存在与服务器的通信,也存在自身本地数据的管理,不像有些系统那样所有数据都依赖服务器(因为网络不总是可用的)。对于这种特定平台上的软件系统,设计时要充分考虑已有的条件,结合具体情况具体分析。此外,本系统属于正在进行的实际项目,最终构想还没有完全确定,因此本文只是初步分析和设计。可能系统需求还会更改,则本文所涉及的内容也会更改。