1.1.2 应用框架的特点
应用框架相比其它程序结构而言具有五大主要特点:模块化、可重用性、可扩展性、简单性和可维护性2,尽管这些特点并非应用框架所完全特有,但它却很好地保持了这些特点的平衡性,对于编写结构复杂、需求多变的大中型应用软件系统而言不啻为最佳选择之一。
模块化
应用框架可以从逻辑上被划分为多个逻辑独立的层次或模块。模块化并非应用框架的独特之处,许多应用程序都具备这个的特点,它的好处是将整个应用独立为多个关联的模块,从而提高了应用的聚合性,降低了应用的耦合性。各个独立的模块通过统一的管道或协议进行通讯互动,这样,当一个模块内部发生重大改变时,只要它的通讯入口和出口保持不变,就不会影响到系统中其它模块的有效性和可靠性。
从开发效率的层面上而言,模块化是实现“人尽其能”的好方式。将应用划分为不同的模块,可以使用不同能力和技术的人员分别担当但同时完成。如B/S结构的应用,可以让美工负责界面端(UI层)的设计,熟悉ASP.NET、JSP的程序员负责应用层,熟悉服务器编程的人员开发Web Service,精通数据库设计的人员负责数据库。这样齐头并进的开发效率较之程序员从头到脚大包大揽无疑高效得多。
可重用性
代码的可重用性是衡量代码质量的一个重要标志。无论是使用函数、类还是其它更高层次的重用模型,都是为了在某种程度上提高重用性,使程序员避免编写重复的代码。而在应用框架中,可重用的不仅仅是函数和类,更包括多个类组成的一套逻辑和设计模式。可以简单地认为,设计框架的主要目的之一便是为了实现代码的重用。
可重用性并不是一件容易办到的事情,相反,设计具有良好可重用性的系统不仅困难而且需要不断迭代式设计。在面向对象语言中,一个类型被其它对象交互引用后,很容易在修复该类型某个逻辑错误时导致其它对象的逻辑错误呈指数级产生,这种所谓的“特征交互作用”是设计致命的逻辑错误之一,也是可重用性的最大敌人。
最简单的代码重用类型是使用函数库(Library),高质量的相关函数可以组合为一个可分发库,但这些函数之间并不一定存在紧密的联系,使用者必须从函数库中找出合适的函数,它的使用效率取决于使用者对函数库的熟悉程度和文档的完善程度。
比函数库复杂一些的是类库,类库提供了类(Class)而非单一的函数,一个类通常会包含具有一些关联关系的函数,使得这些函数更容易区分;除此以外,类库通常还会使用抽象类进行层次设计,这样能够使类的功能函数在使用上更加简单。
设计模式(Design Model)是另一种更高级的重用,它描述的是如何高效地创建面向对象系统的各个部分,如何在某种情况下使用特定的策略来解决具体问题,这种重用涉及到面向对象的方法学。
框架重用是一种集合了类库、设计模式、工作模式(有时还有函数库)的重用模式,它重用的不仅仅是具体功能和解决问题的抽象策略,还包括解决问题的具体流程和规则。从重用程度而言,应用框架是最高级的重用模式。
应用框架与函数库的差别在于,后者只是提供了多组离散的,内部没有或很少量逻辑关系的函数集,这些函数的调用顺序和调用关系并不明确,就好像使用Win32 API开发Windows程序一样,一个简单的窗体设计就必须有上百行代码,而且使用者还必须牢记API的使用顺序;而使用MFC框架编写窗体,代码数量就少的多,程序员需要考虑的内部细节也少得多,因为MFC已经将大量不必要暴露的细节隐藏在框架幕后,开发者不必关心那些通用的、繁琐的实现。除此以外,Visual C++还为开发者提供了多种工作模式,即开发不同类型程序的一般模板、向导和方法,所有这些都是应用框架与一般函数库之间的最大差别。
模块化与可重用性并没有直接的关系,模块化的软件并非都有很好的重用性能,可重用的组件也并非一定被模块化。通常来说,模块化实现分治策略,可重用性是在不同的地方对功能的重复利用3。
可扩展性
可扩展性是应用框架最显著的特征之一,它意味着应用框架的功能具有生长的能力。没有扩展能力的应用框架毫无使用的价值和意义,因为框架本身就是为了提供一个统一的上下文环境给具体的应用使用。应用框架的可扩展性使得我们能够基于一个平台实现不同的功能,满足不同的应用,当然,许多应用需要平台本身的支持。
框架的可扩展性主要是通过继承和聚合两种方式实现的。继承方式是指通过派生类继承基类,通过重用基类的功能并定义新功能的方式实现功能扩展;聚合方式是指调用不同的类型组合为一个新类型而扩展出全新的功能。这两种方法之间并不一定存在最好的模式,开发人员应该在合适的场合使用它们,但一般而言,我们推荐首选聚合而不是继承来扩展功能。
以MFC框架为例,扩展它的主要手段是在继承不同的基类上开发出具有新功能的类而达到扩展目的;在插件式框架中,插件类型则通过实现框架公布的接口完成扩展功能。
简单性
框架的简单性并不能使用框架扩展组件开发的难易程度来衡量,事实上,没有哪一个框架能够保证基于自身开发的程序在逻辑设计和代码工作量上比不使用框架开发更有优势。框架的简单性体现在框架提供了一个明确的工作模式,即开发某种类型扩展插件的一般实现步骤,框架插件内在的关联和管理由框架本身控制而无需框架的使用者考虑,使用者可能根本不熟悉框架的内部协作结构,但扩展插件的开发可以很简单地在统一步骤的基础上进行升华和细化。
框架简单性还体现在它一般都有一个具有内在逻辑关联和丰富功能的“辅助类库”,开发人员能够充分利用框架已经存在的辅助功能和代码。如在.NET Framework中,如安全、加密、数据流等一般功能都完全可以直接从框架类获得而无需程序员自己开发实现。
可维护性
可维护性是业务需求变化后应用能够方便地进行改变的能力。为了使框架能够为不同的应用共享使用,它可以由与业务完全无关的通用组件组成,而应用代码基于这些通用组件基础上实现,这样使应用需求的改变对框架本身的影响降为最低;框架也可以划分多个层次,底层是通用层,而在通用层上的各层逐级加入与不同层次应用相关的元素,这样某个应用改变后的代码修改工作量能够尽量减少而不会牵一发而系全身。
应用框架具备以上这些优点,但它最激动人心的优势莫过于提供了一个统一的“舞台”,并协调了舞台上表演的各位“演员”的内部交互,对于“演员”的成长,框架也提供了一套培养模式和许多额外帮助。
应用框架设计的困难之处在于,设计者如何把握各种应用的共性与特性,并在这些共性与特性基础上抽象出通用的逻辑并能够重用它们;框架设计者如何确定框架的通用点和扩展点,这些通用点和扩展点抽象程度是否合理?
应用框架设计之初的分析工作非常抽象,因此,一开始便要求设计一个完美的框架内容是非常困难的,除非一开始开发人员就有一个完善的需求设计。在相当多的情况下,框架设计者必须改变和调整设计之初对通用点和扩展点的设计;在框架雏形设计完成后,由于新的应用组件加入框架或现存的框架组件发生变化,设计者需要修改框架使它能够适应新的改变。因此,框架设计是一个迭代过程,设计人员必须不断地根据应用的需求进行分析、设计、实现和测试,只有这样,框架雏形才能成长为一个健壮、灵活和具有较高扩展性的平台。