一点感悟

这两天遇到的一些问题,引起的一些思考,觉得有必要写下来。
一. 面向对象的API接口设计,如何做到向后兼容。一个软件存在多个模块,如果提供基础API的模块变化了,那么依赖于它的应用模块都必须重新编译和部署。这就对基础API模块的向后兼容性提出了要求。完全通用的方法是不存在的,任何方法都需要根据实际情况调整,这里仅仅提供一些比较通用但是也不明确的方法:
方法一:扩展时对象只增加方法和属性,原有的属性和方法保留。这对于c++等基于二进制对象布局的方法在使用时需要非常小心,否则极易引起内存访问违规。但是对于ActionScript基于元数据的语言来说,这一方法一般不会有什么问题。对于Java的情况不是非常清楚,估计与actionscript情况差不多。
方法二:增加新的对象(使用继承)提供扩展功能,原来的对象保留。不过对于耦合的类关系,只增加一个类往往并不能达到目的。

这里必须注意的一点是,API提供者与API使用者保持单向依赖的关系,API不应该依赖于具体的应用。对于多模块的软件来说架构最重要的是两点:
1. 从需求中抽象出API,并且将API的开发交给素质较高的人员,而应用之间松散耦合,通过API发生关系。
2. API本身空间也要做划分,将之切割成为正交的空间,这样API扩展时,影响控制在局部。


顺便说说向前兼容的问题,这要求新的Client兼容老的API,这在API设计中很少碰到,但是在设计软件的文档存储格式(Save/Load)时常常遇到,这要求新的应用在开发时,做判断,判断属性不存在时应该如何处理,也就是提供一个默认值。

对于其它的Server-Client结构,比如WebService的扩展,XML扩展等等,我想也应该有类似的方法。所以我也想去看看一些公开的API接口是如何设计和扩展的,比如FaceBook,不过说到底还是抽象与空间划分的问题,而这些并没有通用的方法,都依赖于具体的需求。

二. 面向接口的设计实际上就是合理的划分对象空间。对于对象在扩展时,我们常常会发现并没有办法把它划分成树状的类关系,常常我们发现从一个类A派生了两个类B和C,但是又存在第三种情况,它的行为包含部分B的行为也包含部分C的行为。实际上类的空间划分,和数据库设计是一样的,每一次划分(继承)相当于以一个索引划分对象空间,但是很多时候划分有多个索引,这时候要想划分成单一的一棵树是不可能的。这时候就需要进一步细化对象的空间划分,并将之划分为正交的多个空间。举个例子:Window派生出TransparentWindow和OpaqueWindow,这是一种划分,但是我们又发现另一种划分,WindowWithTitleBar与WindowWithoutTitleBar,他们都是对Window的划分。这时候我们应该想到的是,Window可以拆分为:ITitleBar, IMainWindow,各种Window可以选择实现或者不实现这些接口。当第三者使用这些对象时,直接访问接口即可,因为其它的接口可能是他们并不关心的。当存在多种索引时,将对象拆分为正交的空间,每一个空间尤其自己的单一索引,这应该是对象划分的一种通用原则。就像单根继承一样,这样会使得对象的划分结构非常清晰。
对于某些不是特别复杂的情况,如果存在多种划分索引,不妨用单一的类表示全部的对象,对某些对象,某些属性方法是无效的,这样实际上在简单情况下是很有效的,因为过度的划分会造成复杂性,使用者可能不知道在哪个对象上找到他需要的属性或方法了,这就好像在一张表上设计了全部的属性,尽管有些属性是抵触的,有些属性是相关的。随着不断的扩展,这张表会越来越大,这就需要开始对对象空间做划分了,所以说到底,还是一个需求复杂度的问题,这里最重要的是掌握一个划分的度,何时划分,划分到什么程度,决定这些的往往不仅仅是技术因素,还有商业上,运营上,时间上,成本上的因素,这也是最难判断的一点,需要在实际中去具体问题具体分析,这里就能体现经验的重要性了,其实在架构上方法都是很Genralized的,这些和实现一个具体的算法大部相同,所以设计模式都在讲模式一定有其上下文,也是这个道理吗

胡扯了很多,先到这里吧,等有时间做进一步的整理

posted on 2008-08-15 17:40 雁过无痕 阅读(302) 评论(0)  编辑  收藏


只有注册用户登录后才能发表评论。


网站导航:
 
<2008年8月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
31123456

导航

统计

常用链接

留言簿(7)

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜