http://yvesgao.blogchina.com/2844723.html
摘要:
本文是我的数据库管理系统课程设计的作业。本文以该系统的需求、分析&设计和实现为主线,记录了在开发过程中我使用的方法,遇到的问题以及一些心得。应该说这是我目今程序设计思想的总结。另外,本文也阐述了我所认为的个人软件开发的一般过程。
写在正文前面:
编程序也有些许时日了,觉得最明显的长进就是双手十指变得灵活非常,打字很快了还练就了盲打,可渐渐的手太快脑子却跟不上趟了。论语说,学而不思则怠,确实是有些怠了。
我不想只做coder。
后来接触并了解了一些面向对象的思想,越来越欣喜,因为眼前豁然开朗,发觉开始远离coder了。
正文:
一、 需求
1、 如何开始
Grady Booch说,如果你面对一个问题,不知道如何入手,就从你确实能够理解的地方入手。
这个所谓“确实能够理解的地方”到底在哪呢?很明显用户需求是这样一个地方,原因很简单,作为用户使用软件当然要比开发这个软件容易的多。这也是目标导向方法所倡导的,因为最终用户是软件的真正验收者,只有他们有决定权,好与不好全凭他们的好恶,仍是那句话,用户是上帝。
MiniDatabase的需求不用我太费心,因为已经写到了课程设计指导书上,这里我的老师就是上帝了:)。
如下的几点需求值得庆幸——因为少,但要想继续进行开发就要更深入的分析。
2、 用例分析
无疑,用例分析是一个优秀的深入分析的方法,它仍然是目标导向的,但更细致不仅是罗列功能的描述而是功能实现后用户看到的和一些必要但看不到的软件行为。我认为一份优秀的深入的用例分析可以整理成一份软件的使用手册。
听上去很“神奇”,软件还没开发出来——实际上一行代码还未写过,使用手册就可以预先写成,似乎本末倒置。
这其实来源于一种认识,设想如果我们的上帝具有与我们同等的技术力,那么他一定能开发出自己满意的产品。那么要上帝学习我们的技术么?显然,这太难了,还是让我们学习上帝的赏析理念和好恶准则吧——我们得扮演上帝,相比之下,这会简单些。
对于将要建成的系统来讲,用例是接口,是表层的系统行为,一定得把握住这一点,在这个阶段我们只思考表层的系统行为,我们得集中精力一步步把事情做好。
用例还有两个好处就是文档化和标准化
文档化的用例可以纠正我们在实际和实现阶段出现的偏离轨道的行为,你得时刻拿它出来和现行的工作对照,千万不能出现偏差,用例其实就是“圣经”,因为它记录了上帝的要求。
标准化的用例用于交流和比较,用例展现了统一的风格,比如完成相似工作的用例应该有相似的工作流。
凡此种种,用例为纲,纲举目张。
MiniDatabase的用例较为简单但挺长的,为了行文的流畅,我把它放到附录里了。
二、 分析&设计——在题域与解域边缘
1、 如何开始
用例只能帮助我们从“上帝”的角度认知应用系统,但说实话,这样不能为我们的系统添上哪怕一砖一瓦,我们要想继续开展工作,还得做些衔接性的活计。
上一个阶段,我们所做的需求分析工作,其实是划定了一个“上帝”所处的领域,至少是和我们系统相关的领域。
在需求分析的文档理一定充斥着大量同样或相近的词汇(这要求我们用词得规范些),我们得总结这些相同、相近的词汇,这些词有的代表某个动作、某个物件或联系等,其实这些词足以代表领域的系统范围。
我们需要对这个系统建模,得打起十二分精神,这就好像万丈高楼的设计图,平地起就靠它了。
前面分析出的许多词汇,我将其统称为概念。
我认为,建模的实质无非是以解域工具描述题域概念进而解决问题的方法。
领域建模主要就是针对这些概念进行建模,概念本属题域,与解域有颇多隔膜,将其转换至解域则颇费周章,所以拉近解域与题域则是建模方法的研究方向。
面向对象的方法便占此擅场,正如Bruce Eckle 所说,“”虽然有些夸张但确是精要所在。
MiniDatabase即是以oo的思想指导完成的,下面我就详述这一过程。
2、 题域建模
2.1理析概念
我认为对概念建模是获得良好设计的敲门砖,并且将会贯穿整个设计阶段,当陷入迷茫时深入理解“概念”将使你重回正道。
我们这个MiniDatabase里有这样一些概念:MiniDatabase是一个数据库管理系统,数据库包含多个数据表和查询,每个数据表和查询包含唯一一个表模式和多条记录,每条记录有多个单元,每个单元又有……
上面这段话是对需求分析的一个提炼,这是从题域向解域迈出的第一步,几个概念已经很清晰了:数据库,数据表,查询,表模式,记录,单元……
对应于面向对象的思想,这些就是对象,例如:数据库对象即是题域概念数据库的解域描述,你能发现用面向对象的方法,题域中有什么就可以拿到解域中把它作为对象,一切都那么自然。
对象之间的关系也是一种,也需要被建模,如:数据库包含数据表和查询,这句话中就有两个关系——包含和关联。
通常不能希冀一次就归纳出所有的概念,很显然这不符合人们认知事物循序渐进的规律,例如,在实现阶段发现了新的概念你仍然可以回过头来修改设计——这也就是所谓的迭代。
有些专家和书籍还是推荐将分析和设计做得尽可能的细致以避免反工,理论上确是应花费大量的时间进行分析和设计,不过这些毕竟是抽象的,通常得有积年累月的开发经验;还有的方法倾向于短期的迭代,这相当于不停的测试,有时这很浪费时间,毕竟,在一定范围内大脑的抽象能力还是搞得定的。
所以还是随心所欲吧感觉找不到概念时就像下进行吧。
2.2对象的职责和状态
对题域概念的解域建模并不仅停留在理析概念的阶段,更深入的我们得认知对象的行为和状态。
2.2.1什么是对象的职责?
这个问题看似简单。比如在 MiniDatabase 中,我想创建一个数据表,这是谁的职责呢?是数据表自身么?显然不是,这不符合逻辑,那么一定是数据表的拥有者——数据库,似乎合理,但更合逻辑的,该职责应归附MiniDatabase管理器,由管理器搜集相关信息,创建一个数据表,然后传递给数据表的拥有者,并由其保存和维护,所以数据库的职责是管理和组织而不是创建(其实这个例子说明了一个常见的设计,即创建和维护的解耦,后面还会提到)。
对象的职责有大有小,有表有里,一个大的或表层的职责可能有几个小的里层的职责完成,将大的分割成几个小的是一个很常用的方法(这是由人认知的局限性造成的)。
一个对象的职责也可能委托给其他的对象。
对于对象职责的划分似乎没有一定之规,也没有好坏之分,只有合适与不适之分,所谓合适与不适往往又要通过后续的工作来检验,所以这又是依靠经验才能做好的事情,但我感觉很多时候只要把握住题域概念,思考其在题域中的职责,理清其中的逻辑关系,对应过来还是能得到一个较为合适的职责划分的。
2.2.2什么是对象的状态
对象通过状态区别自己和其他对象,比如一个数据库包含多个数据表,如何区别这些表呢?可以通过表名字,这名字就是表的状态了。
一般状态是和职责关联的,一些状态可能决定了职责,一些职责可能启发出某些状态。
状态的分析比职责更隐晦,因为大多数情况下,职责是表现于对象之外的,而状态则内储于对象之中。
2.3将对象变成类
从特殊到一般是认知的普遍规律之一,从对象到类就遵循了这一规律。
为什么要将对象变成类?
将对象变成类是又一次抽象,是一次归纳和整理,得确信题域中是有某种规律或定式的,认知这些能让我们从全局来把握题域,好处之一就是应付题域的变化——所谓万变不离其宗,握其宗本则为执牛耳者了。
依凭对对象的认识——职责和状态,我们对其分门别类,划归类似的职责和状态而成一类,几小类又合并成一大类,由此可建立一个类的体系。如图:
在MiniDatabase中,数据表和查询是一类,因为查询是一个有条件的数据表。数据库和数据标也是一类,因为他们都包含其它的对象,如此等等……
划归一类的原因可能很明显(如查询和数据表),也可能很抽象(如数据库和数据表),一般越向类体系上溯,其分类原则越抽象,但必须合乎概念和逻辑,类的划分也应是以概念为准绳的。
我仍想强调,要构造优秀的类体系图,请紧紧把握题域概念。如果确实做到了这一点,不妨称此为概念类,对象则为概念对象。
3、 解域建模
进入解域之前,你得确信题域的工作已经差不多了,一个检验的办法是:看看是不是所有的概念已经出现在类体系图中了。千万不要太仓促,急于求成只能使你陷入两难境地——推翻设计但又缺少时间,还是草草了事而容忍一堆难于维护的代码。
这一节我将更加贴近MiniDatabase,具体说说MiniDatabase是如何架构的。
3.1设计模式
对于新手来说,题域建模比解域建模容易,但对于那些经验丰富的人,更令其头疼的却是题域,他们可能会被用户一天一变的需求搞的焦头烂额,但在解域却游刃有余。
为什么呢?
因为,解域里存在大量的定式,更专业一点叫模式,解域里的定式一部分被称为设计模式。
至于何时向模型引入模式,我想可以从两个方面思考,一是为了向系统提供某种特性——通常是灵活性;二是凭经验对某些典型问题应用模式会带来好处。
3.1.1Composite模式
Composite模式用来表示对象的部分——整体层次结构。一般来讲,似乎稍具规模的应用都应该有所谓“对象的部分——整体层次结构”,所以上来先试试Composite模式会使解域建模的突破口。
这种有多个抽象层次的模式主要目的就是为其继承层提供统一的访问接口,从概念上讲就是抽象、泛化,抽象层次多了就可以将不同的接口放到不同的层次上,这样就对接口进行了归类,比如下图:
在图中,对于Database,它既需要Add、Delete……接口来管理其子对象,又需要Save,Load接口来保存自己,但你不能将这些接口放到同一个抽象层上——比如CdataCollection,显然CDataLeaf没有子对象,也就没有Add、Delete接口。
刚才提到了支持对象管理的Add、Delete接口,这些接口的实现仍是委托给一个已有的容器型对象。
在我看来Composite模式的另一个重要之处就是把题域模型与解域模型联合起来。
4、 小结
前面花了大量篇幅讲述了如何进行题域建模和解域建模,我想应该感到,由于面向对象方法的引入使题域和解域的界限渐渐模糊,比如对象和类出现在题域也在解域发挥重要作用。
实际上任何建模的方法都致力于拉近题域与解域,面向对象的方法正占此擅场。应该说,面向对象的思想结合UML的表达力,就可以贯通题域与解域了。
正如本章标题所写:“分析&设计——在题域与解域边缘”
分析和设计同属“从题域过渡到解域的阶段”,有些书籍倾向于将分析和设计隔离开,我认为分析和设计同在题域与解域的边缘,他们交织在一起,很难说分析只针对题域,设计只针对解域,只能说分析注重题域,设计注重解域,而其中的联系——即如何平滑的从题域过渡到解域却是重中之重,由此将其分门别类的隔离开却是过于武断了,所以文中之用题域建模和解域建模来类比的描述这两个概念。
题域与解域的交叠确实常常困扰我,比如,在分析时我常常发现自己在考虑是否使用一个Observe模式,抑或是在设计时发现某个概念类应继承在另一个之下,一段时间的焦灼让我豁然,我想也不必拘泥于分清分析和设计阶段,超前进行设计,回头返工分析都是自然的,前者能帮助平滑过渡,后者则避免一些重构。
分析和设计的工作实在很大(有所谓70%/30%理论,即70%的时间花在前期的需求、分析和设计,30%则花在后期的实现、测试和布置),前面之叙述了主体部分,后面一小节说些我的点滴心得,徒做拾遗。