五、总观Application Framework

来源:互联网 发布:远程wifi控制软件 编辑:程序博客网 时间:2024/05/16 06:32

带艺术气息的软件创作行为将在Application Framework出现后逐渐成为工匠技术,
而我们都将成为软件IC装配厂里的男工女工。
但,不是亨利福特,我们又如何能够享受大众化的汽车?
或许以后会出现「纯手工精制」的软件,可我自己从来不嫌机器馒头难吃。


什么是Application Framework ?


还没有学习任何一套Application Framework  的使用之前,就给你近乎学术性的定义,我可以想象对你而言绝对是「形而上学的」(超物质的无形哲理),尤其如果你对对象导向(Object Oriented)也还没有深刻体会的话。形而上者谓之道,形而下者谓之器,我想能够舍器而直接近道者,几稀!但是,「定义」这种东西又似乎宜开宗明义摆在前头。我诚挚地希望你在阅读后续的技术章节时能够时而回来看看这些形而上的叙述。当你有所感受,技术面应该也进入某个层次了。


侯捷怎么说

首先我们看看侯捷在其无责任书评中是怎么说的:


演化(revolution)永远在进行,但这个世界却不是每天都有革命性(revolution)的事物发生。动不动宣称自己(或自己的产品)是划时代的革命性的,带来的影响就像时下满街跑的大师一样使我们渐渐无动于衷(大师不可能满街跑)  ! 但是ApplicationFramework  的的确确在我们软件界称得上具有革命精神。


什么是Application Framework?Framework 这个字眼有组织、框架、体制的意思,Application Framework不仅是一般性的泛称,它其实还是对象导向领域中的一个专有名词。


基本上你可以说,Application Framework是一个完整的程序模型,具备标准应用软件所需的一切基本功能,像是文件存取、打印预视、资料交换... ,以及这些功能的使用接口(工具栏、状态列、菜单、对话框)。如果更以术语来说, Application Framework就是由一整组合作无间的「对象」架构起来的大模型。喔不不,当它还没有与你的程序产生火花的时候,它还只是有形无体,应该说是一组合作无间的「类别」架构起来的大模型。这带来什么好处呢?程序员只要带个购物袋到「类别超级市场」采买,随你要买MDI 或OLE 或ODBC 或Printing Preview,回家后就可以轻易拼凑出一个色香味俱全的大餐。「类别超级市场」就是C++ 类别库,以产品而言,在Microsoft是MFC ,在Borland是OWL ,在IBM 则是OpenClass。这个类别库不只是类别库而已,传统的函数库(CRuntime 或Windows API)乃至于一般类别库提供的是生鲜超市中的一条鱼一支葱一颗大白菜,彼此之间没有什么关联,主掌中馈的你必须自己选材自己调理。能够称得上Application Framework者,提供的是火锅拼盘(就是那种带回家通通丢下锅就好的那种),依你要的是白菜火锅鱼头火锅或是麻辣火锅,菜色带调理包都给你配好。当然这样的火锅拼盘是不能够就地吃的,你得给它加点能量。放把火烧它吧,这火就是所谓的application object(在MFC程序中就是衍生自CWinApp的一个全域性对象)。是这个对象引起了连锁反应(一连串的'new' ),使每一个形(类别)有了真正的体(对象),把应用程序以及Application Framework  整个带动起来。一切因缘全由是起。Application Framework带来的革命精神是,程序模型已经存在,程序员只要依个人需求加料就好:在衍生类别中改写虚拟函数,或在衍生类别中加上新的成员函数。这很像你在火锅拼盘中依个人口味加盐添醋。


由于程序代码的初期规模十分一致(什么样风格的程序应该使用什么类别,是一成不变的),而修改程序以符合私人需要的基本动作也很一致(我是指像「开辟一个空的骨干函数」这种事情),你动不了Application Framework  的大架构,也不需要动。这是福利不是约束。


应用程序代码骨干一致化的结果,使优越的软件开发工具如CASE(Computer AidSoftware Engineering )tool  容易开发出来。你的程序代码大架构掌握在ApplicationFramework  设计者手上,  于是他们就有能力制作出整合开发环境(  IntegratedDevelopment Environment,IDE )了。这也是为什么Microsoft、Borland、Symantec 、Watcom、IBM 等公司的整合开发环境进步得如此令人咋舌的原因了。有人说工学院中唯一保有人文气息的只剩建筑系,我总觉得信息系也勉强可以算上。带艺术气息的软件创作行为(我一直是这么认为的)将在Application Framework  出现后逐渐成为工匠技术,而我们都将只是软件IC装配厂里的男工女工。其实也没什么好顾影自怜,功成名就的冠冕从来也不曾落在程序员头上;我们可能像纽约街头的普普(POP )工作者,自认为艺术家,可别人怎么看呢?不得而知!话说回来,把开发软件这件事情从艺术降格到工技,对人类只有好处没有坏处。不是亨利福特,我们又如何能够享受大众化的汽车?或许以后会出现「纯手工精制」的软件,谁感兴趣不得而知,我自己嘛... 唔... 倒是从来不嫌机器馒头难吃。


如果要三言两语点出Application Framework  的特质,我会这么说:我们挖出别人早写好的一整套模块(MFC 或OWL 或OpenClass)之中的一部份,给个引子(applicationobject)使它们一一具象化动起来,并被允许修改其中某些零件使这程序更符合私人需求,如是而已。



我怎么说


侯捷的这一段话实在已经点出Application Framework的精神。凝聚性强、组织化强的类别库就是Application Framework。一组合作无间的对象,彼此藉消息的流动而沟通,并且互相调用对方的函数以求完成任务,这就是Application Framework。对象存在哪里?在MFC 中?! 这样的说法不是十分完善,因为MFC 的各个类别只是「对象属性(行为)的定义」而已,我们不能够说MFC 中有实际的对象存在。唯有当程序被applicationobject(这是一个衍生自MFC CWinApp 的全域对象)引爆了,才将我们选用的类别一一具象化起来,产生实体并开始动作。图5-1  是一个说明。


这样子说吧,静态情况下MFC 是一组类别库,但在程序执行时期它就生出了一群有活动力的对象组。最重要的一点是,这些对象之间的关系早已建立好,不必我们(程序员)操心。好比说当使用者按下菜单的【File/Open】项,开文件对话框就会打开;使用者选好档名后,Application Framework  就开始对着你的资料类别,唤起一个名为Serialize的特殊函数。这整个机制都埋好了,你只要把心力放在那个叫作Serialize的函数上即可。


选用标准的类别,做出来的产品当然就没有什么特色,因为别人的零件和你的相同,兜起来的成品也就一样。我指的是使用者接口(UI)对象。但你要知道,软件工业发展到现阶段这个世代,着重的已不再是UI 的争奇斗艳,取巧哗众;UI 已经渐渐走上标准化了。软件一决胜负的关键在资料的处理。事实上,在「真正做事」这一点,整个application framework  是无能为力的,也就是说对于数据结构的安排,数据的处理,数据的显示,Application Framework  所能提供的,无一不是单单一个空壳而已--在C++ 语言来讲就是个虚拟函数。软件开发人员必须想办法改造(override)这些虚拟函数,才能符合个人所需。基于C++ 语言的特性,我们很容易继承既有之类别并加上自己的特色,这就是物件导向程序设计的主要精神。也因此,C++ 语言中有关于「继承」性质的份量,在MFC程序设计里头占有很重的比例,在学习使用MFC 的同时,你应该对C++ 的继承性质和虚拟函数有相当的认识。第2章有我个人对C++ 这两个性质的心得。




假设你买了一个整厂整线计划,包括仓贮、物料、MIS、生管,各个部门之间的搭配也都建立起来了,包含在整厂整线计划内。这个厂原先是为了生产葡萄酒,现在改变主意要生产白兰地,难道整个厂都不能用了吗?不!只要把进货原料改一改、发酵程序改一改、瓶装程序改一改、整个厂的其它设备以及设备与设备之间的联机配合(这是顶顶重要的)都可以再利用。物料之后到生管,装瓶之后到仓贮,仓贮之后到出货,再加上MIS监控全厂,这些程序都是不必改变的。


一个整厂整线计划,每一单元之间的联机沟通,合作关系,都已经建立起来,是一种建构好的运作模式。抽换某个单元的性质或部份性质,并不影响整体操作。「整厂整线」最重要最有价值的是各单元之间的流程与控制。


反映到对象导向程序设计里头,Application Framework  就是「整厂整线规划」,Application Framework提供的类别就是上述工厂中一个一个的单元。最具价值的就是各类别之间的交互运作模式。


虽然文件读写(此动作在MFC 称为Serialize)单元必须改写以符合个人所需,但是单元与单元之间的关系依然存在而且极富价值。当使用者在程序中选按【File/Open】或【File/Save 】,主框窗口自动通知Document 对象(内存资料),引发Serialization 动作;而你为了个人的需求,改写了这个Serialize虚拟函数。你对MFC的改写范围与程度,视你的程序有多么特异而定。


可是如果酿酒厂想改装为炼钢厂?那可就无能为力了。这种情况不会出现在软件开发上,因为软件的必备功能使它们具有相当的相似性(尤其Windows 又强调接口一致性)。好比说程序想支持MDI 接口,想支持OLE ,这基本上是超越程序之专业应用领域之外的一种大格局,一种大架构,最适合Application Framework发挥。


很明显,Application Framework  是一组超级的类别库。能够被称为Framework  者必须其中的类别性质紧密咬合,互相呼应。因此你也就可以想象,Framework  所提供的类别是一伙的,不是单片包装的。你把这伙东西放入程序里,你也就得乖乖遵循一种特定的(Application Framework  所规定的)程序风格来进进程序设计工作。但是侯捷也告诉我们,这是福利不是约束。



别人怎么说


其它人又怎么看Application Framework?我将胪列数篇文章中的相关定义。若将原文译为中文,我恐怕力有未逮辞不达意,所以列出原文供你参考。


1985 年,Apple公司的MacApp 严格而系统化地定义出做为一个商业化Application Framework所需要的关键理念:



*cohesive 的意思是强而有力、有凝聚力的


*steroid 是类固醇。自从加拿大100 公尺名将班强生在汉城奥运吃了这药物而夺得金牌并打破世界记录,相信世人对这个名称不会陌生(当然强生的这块金牌和他的世界记录后来是被取消的)。类固醇俗称美国仙丹,是一种以胆固醇结构为基础,衍生而来的荷尔蒙,对于发炎红肿等症状有极速疗效。然而因为它是透过抑制人类免疫系统而得到疗效,如果使用不当,会带来极不良的副作用。运动员用于短时间内增强身体机能的雄性激素就是类固醇的一种,会影响脂肪代谢,服用过量会导至极大的副作用。


基本上MacApp 以类固醇来比拟Application Framework  虽是妙喻,但类固醇会对人体产生不好的副作用而Application Framework  不会对软件开发产生副作用--  除非你认为不能随心所欲写你的码也算是一种副作用。


Apple  更一步更明确地定义一个Application Framework 是:


* 这里所指的support 并不只是视觉性UI 组件如menu、dialog、listbox...,还包括一个应用程序所需要的其它功能设备,像是Document, View, Printing, Debugging。


另一个相关定义出现在Ray Valdes  于1992 年10 月发表于Dr. Dobb's Journal  的"Sizing upApplication Frameworks and Class Libraries" 一文之中:


Donald G. Firesmith 在一篇名为"Frameworks : The Golden path of the object Nirvana" 的文章中对Application Framework  有如下定义:



Bjarne Stroustrup(C++ 原创者)在他的The C++ Programming Language 一书中对于Application Framework  也有如下叙述:



Kaare Christian 在1994/02/08  的PC Magazine  中有一篇"C++ Application Frameworks"文章,其中有下列叙述(节录):
两年前我在纽约北边的乡村盖了一栋post-and-beam 房子。在我到达之前我的木匠已经把每一根梁的外形设计好并制作好,把一根根的粗糙木材变成一块块锯得漂漂亮亮的零件,一切准备就线程只待安装。(注:所谓post-and-beam 应是指那种梁柱都已规格化,可以邮购回来自己动手盖的DIY Do It Yourself -- 房子)。使用Application Framework 建造一个Windows 应用程序也有类似的过程。你使用一组早已做好的零件,它使你行进快速。由于这些零件坚强耐用而且稳固,后面的工作就简单多了。但最重要的是,不论你使用规格化的梁柱框架来盖一栋房子,或是使用Application Framework 来建立一个Windows 程序,工作类型已然改变,出现了一种完全崭新的做事方法。在我的post-and-beam 房子中,工作类型的改变并不总是带来帮助;贸易商在预制梁柱的技巧上可能会遭遇适应上的困扰。同样的事情最初也发生在Windows身上,因为你原已具备的某些以C语言写Windows程序的能力,现在在以C++和Application Framework开发程序的过程中无用武之地。时间过去之后,Windows 程序设计的类型移转终于带来了伟大的利益与方便。Application Framework本身把message loops 和其它Windows的苦役都做掉了,它促进一个比较秩序井然的程序结构。


Application Framework -- 建立Windows 应用软件所用的C++ 类别库-- 如今已行之有年,因为对象导向程序设计已经快速地获得了接受度。Windows API 是程序性的,Application Framework 则让你写对象导向式的Windows 程序.它们提供预先写好的机能(以C++ 类别型式呈现出来),可以加速应用软件的开发。


Application Framework 提供数种优点.或许最重要的,是它们在对象导向程序设计模式下对Windows  程序设计过程的影响。你可以使用Framework  来减轻例行但繁复的琐事,目前的Application Framework 可以在图形、对话框、打印、求助、OCX  控制组件、剪贴簿、OLE 等各方面帮助我们,它也可以产生漂亮的UI  接口如工具栏和状态列。借着Application Framework 的帮助写出来的码往往比较容易组织化,因为Framework改变了Windows  管理消息的方法。也许有一天Framework  还可以帮你维护单一一套码以应付不同的执行平台。


你必须对Application Framework 有很好的知识,才能够修改由它附带的软件开发工具制作出来的骨干程序。它们并不像Visual Basic 那么容易使用。但是对ApplicationFramework  专家而言,这些程序代码产生器可以省下大量时间。使用Application Framework 的主要缺点是,没有单一一套产品广被所有的C++  编译器支持。所以当你选定一套Framework,在某个范围来说,你也等于是选择了一个编译器。



为什么使用Application Framework


虽然Application Framework并不是新观念,它们却在最近数年才成为PC 平台上软件开发的主流工具。对象导向语言是具体实现Application Framework  的理想载具,而C++ 编译器在PC 平台上的出现与普及终于允许主流PC 程序员能够享受Application Framework  带来的利益。


从八十年代早期到九十年代初始,C++ 大都存在于UNIX  系统和研究人员的工作站中,不在PC 以及商业产品上。C++ 以及其它的对象导向语言(例如Smalltalk-80)使一些大学和研究计划生产出现今商业化Application Framework  的鼻祖。但是这些早期产品并没有明显区隔出应用程序与Application Framework之间的界线。


今天应用软件的功能愈来愈复杂,建造它们的工具亦复如此。Application Framework、ClassLibrary 和GUI toolkits 是三大类型的软件开发工具(请见方块说明),这三类工具虽然以不同的技术方式逼近目标,它们却一致追求相同而基本的软件开发关键利益:降低写程序代码所花的精力、加速开发效率、加强可维护性、增加强固性(robustness)、为组合式的软件机能提供杠杆支点(有了这个支点,再大的软件我也举得起来)。


当我们面临软件工业革命,我们的第一个考量点是:我的软件开发技术要从哪一个技术面切入?从raw API  还是从高阶一点的工具?如果答案是后者,第二个考量点是我使用哪一层级的工具?GUI toolkits 还是Class Library 还是Application Framework?如果答案又是后者,第三个考量点是我使用哪一套产品?MFC 或OWL 或Open Class Library ?(目前PC 上还没有第四套随编译器附赠的Application Framework  产品)


别认为这是领导者的事情不是我(工程师)的事情,有这种想法你就永远当不成领导者。也别认为这是工程师的事情不是我(学生)的事情,学生的下一步就是工程师;及早想点工业界的激烈竞争,对你在学生阶段规划人生将有莫大助益。


我相信,Application Framework  是最好的杠杆支点。



Application Framework,Class Library,GUI toolkit


一般而言,Class Library 和GUI toolkit 比Application Framework  的规模小,定位也没那么高阶宏观。Class Library 可以定义为「一组具备对象导向性质的类别,它们使应用程序的某些功能实现起来容易一些,这些功能包括数值运算与数据结构、绘图、内存管理等等等;这些类别可以一片一片毫无瓜葛地并入应用程序内」。请特别注意这个定义中所强调的「一片一片毫无瓜葛」,而不像ApplicationFramework  是大伙儿一并加入。因此,你尽可以随意使用Class Library,它并不会强迫你遵循任何特定的程序架构。Class Library 通常提供的不只是UI 功能、也包括一般性质的机能,像数据结构的处理、日期与时间的转换等等。GUI toolkit 提供的服务类似Class Library,但它的程序接口是程序导向而非对象导向。而且它的功能大都集中在图形与UI 接口上。GUI toolkit 的发展历史早在对象导向语言之前,某些极为成功的产品甚至是以汇编语言(assembly )写成。不要必然地把GUI 联想到Windows,GUI toolkit 也有DOS 版本。我用过的Chatter Box 就是DOS 环境下的GUI 工具(是一个函数库)。


使用Application Framework  的最直接原因是,我们受够了日益暴增的Windows API。把MFC 想象为第四代语言,单单一个类别就帮我们做掉原先要以一大堆APIs 才能完成的事情。


但更深入地想,Application Framework  绝不只是为了降低我们花在浩瀚无涯的WindowsAPI  的时间而已;它所带来的对象导向程序设计观念与方法,使我们能够站在一群优秀工程师(MFC 或OWL 的创造者)的努力心血上,继承其成果而开发自己之所需。同时,因为Application Framework  特殊的工作类型,整体开发工具更容易制作,也制作的更完美。在我们决定使用Application Framework  的同时,我们也获得了这些整合性软件开发环境的支持。在软件开发过程中,这些开发工具角色之吃重不亚于Application Framework本身。


Application Framework  将成为软件技术中最重要的一环。如果你不知道它是什么,赶快学习它;如果你还没有使用它,赶快开始用。机会之窗不会永远为你打开,在你的竞争者把它关闭之前赶快进入!如果你认为改朝换代还早得很,请注意两件事情。第一,江山什么时候变色可谁也料不准,当你埋首工作时,外面的世界进步尤其飞快;第二,物件导向和Application Framework  可不是那么容易学的,花多少时间才能登堂入室可还得凭各人资质和基础呢。


浩瀚无涯的Windows API



Microsoft Foundation Classes(MFC)


PC 世界里出了三套C++ Application Frameworks,并且有愈多愈多的趋势。这三套是Microsoft 的MFC (Microsoft Foundation Classes ),Borland 的OWL (ObjectWindowLibrary),以及IBM VisualAge C++  的Open Class Library 。至于其它C++ 编译器厂商如Watcom、Symantec 、Metaware,只是供应整合开发环境(Integraded DevelopmentEnvironment,IDE ),其Application Framework  都是采用微软公司的MFC。



早初,开发Windows 应用程序必须使用微软的SDK(Software Development Kit ),直接调用Windows API 函数,向Windows 操作系统提出各种要求,例如配置内存、开启窗口、输出图形... 。



数以千计的Windows APIs,每个看起来都好象比重相若(至少你从手册上看不出来孰轻孰重)。有些APIs 彼此虽有群组关系,却没有相近或组织化的函数名称。星罗棋布,雾列星驰;又似雪球一般愈滚愈多,愈滚愈大。撰写Windows 应用程序需要大量的耐力与毅力,以及大量的小心谨慎!


MFC 帮助我们把这些浩繁的APIs,利用对象导向的原理,逻辑地组织起来,使它们具备抽象化、封装化、继承性、多态性、模块化的性质。


1989 年微软公司成立Application Framework  技术团队,名为AFX 小组,用以开发C++对象导向工具给Windows 应用程序开发人员使用。AFX 的"X"  其实没有什么意义,只是为了凑成一个响亮好念的名字。


这个小组最初的「宪章」,根据记载,是要"utilize the latest in object oriented technology to provide tools and libraries for developers writing the most advanced GUI applications on the market",其中并未画地自限与Windows 操作系统有关。果然,其第一个原型产品,有自己的窗口系统、自己的绘图系统、自己的对象数据库、乃至于自己的内存管理系统。当小组成员以此产品开发应用程序,他们发现实在是太复杂,又悖离公司的主流系统--Windows --  太遥远。于是他们修改宪章变成"deliver the power of object-oriented solutions to programmers to enable them to build world-class Windows based applications in C++."  这差不多正是Windows 3.0 异军崛起的时候。


C++ 是一个复杂的语言,AFX 小组预期MFC 的使用者不可能人人皆为C++ 专家,所以他们并没有采用所有的C++ 高阶性质(例如多重继承)。许多「麻烦」但「几乎一成不变」的Windows 程序动作都被隐藏在MFC 类别之中,例如WinMain  、
RegisterClass、Window Procedure 等等等。



为了让MFC 尽可能地小,尽可能地快,AFX 小组不得不舍弃高度的抽象(导至过多的虚拟函数),而引进他们自己发明的机制,尝试在对象导向领域中解决Windows 消息的处理问题。这也就是本书第9章深入探讨的Message Mapping 和Message routing 机制。注意,他们并没有改变C++ 语言本身,也没有扩大语言的功能。他们只是设计了一些令人拍案叫绝的宏,而这些宏背后隐藏着巨大的机制。


了解这些宏(以及它们背后所代表的机制)的意义,以及隐藏在MFC 类别之中的那些足以曝露原型机密的「麻烦事儿」,正是我认为掌握MFC 这套Application Framework的重要手段。


就如同前面那些形而上的定义,MFC 是一组凝聚性强、组织性强的类别库。如果你要利用MFC 发展你的应用程序,必须同时引用数个必要类别,互相搭配奥援。图5-3  是一个标准的MFC 程序外貌。隐藏在精致画面背后更重要的是,就如我在前面说过,对象与对象之间的关系已经存在,消息的流动程序也都已设定。当你要为这个程序设计真正的应用功能,不必在意诸如「我如何得知使用者按左键?左键按下后我如何激活某一个函数?参数如何传递过去... 」等琐事,只要专注在左键之后真正要做的功能动作就好。



白头宫女话天宝:Visual C++  与 MFC


微软公司于1992/04  推出C/C++ 7.0 产品时初次向世人介绍了MFC 1.0,这个初试啼声的产品包含了20,000 行C++ 源代码,60 个以上的Windows 相关类别,以及其它的一般类别如时间、数据处理、文件、内存、诊断、字符串等等等。它所提供的,其实是一个"thin and efficient C++ transformation of the Windows API" 。其32 位版亦在1992/07  随着Win32 SDK 推出。


MFC 1.0 获得的回响带给AFX 小组不少鼓舞。他们的下一个目标放在:

 ■更高阶的架构支持


 ■罐装组件(尤其在使用者接口上)


前者成就了Document/View  架构,后者成就了工具栏、状态列、打印、预览等极受欢迎的UI 性质。当然,他们并没有忘记兼容性与移植性。虽然AFX 小组并未承诺MFC 可以跨不同操作系统如UNIX XWindow 、OS/2 PM 、Mac System 7,但在其本家(Windows 产品线)身上,在16 位Windows 3.x 和32 位Windows 95 与Windows NT 之间的移植性是无庸置疑的。虽然其16 位产品和32 位产品是分别包装销售,你的原始码通常只需重新编译联结即可。


Visual C++ 1.0(也就是C/C++ 8.0)搭配MFC 2.0 于1993/03  推出,这是针对Windows3.x 的16 位产品。接下来又在1993/08  推出在Windows NT 上的Visual C++ 1.1 forWindows NT,搭配的是MFC 2.1。这两个版本有着相同的基本性质。MFC 2.0 内含近60,000 行C++ 程序代码,分散在100  个以上的类别中。Visual C++  整合环境的数个重要工具(大家熟知的Wizards)本身即以MFC 2.0 设计完成,它们的出现对于软件生产效率的提升有极大贡献。


微软在1993/12又推出了16 位的Visual C++ 1.5,搭配MFC 2.5。这个版本最大的进步是多了OLE2 和ODBC 两组类别。整合环境也为了支持这两组类别而做了些微改变。1994/09,微软推出Visual C++ 2.0,搭配MFC 3.0,这个32 位版本主要的特征在于配合目标操作系统(Windows NT 和Windows 95),支持多执行线程。所有类别都是thread-safe 。UI 对象方面,加入了属性表(Property Sheet )、miniframe 窗口、可随处停驻的工具栏。MFC collections 类别改良为template-based。联结器有重大突破,原使用的Segmented Executable Linker  改为Incremental Linker ,这种联结器在对OBJ 档做联结时,并不每次从头到尾重新来过,而只是把新资料往后加,旧资料加记作废。想当然耳,EXE 档会累积许多不用的垃圾,那没关系,  透过Win32 memory-mapped file, 操作系统(Windows NT 及Windows 95)只把欲使用的部份加载,丝毫不影响执行速度。必要时程序员也可选用传统方式联结,这些垃圾自然就不见了。对我们这些终日受制于editbuild-run-debug 轮回的程序员, Incremental Linker可真是个好礼物。


1995/01,微软又加上了MAPI(Messaging API)和WinSock 支持,推出MFC 3.1(32 位元版),并供应13 个通用控制组件,也就是Windows 95 所提供的tree 、tooltip 、spin 、slider、progress、RTF edit  等等控制组件。


1995/07,MFC 有了3.2 版,那是不值一提的小改版。


然后就是1995/09  的32 位MFC 4.0。这个版本纳入了DAO 数据库类别、多执行线程同步控制类别,并允许制作OCX containers。搭配推出的Visual C++ 4.0 编译器,也终于支持了template 、RTTI 等C++ 语言特性。IDE  整合环境有重大的改头换面行动,ClassView、Resource View 、File View 都使得项目的管理更直觉更轻松,Wizardbar 则活脱脱是一个简化的ClassWizard。此外,多了一个极好用的Components Gallery,并允许程序员订制AppWizard 。


1996 年上半年又推出了MFC 4.1,最大的焦点在ISAPI (Internet Server API )的支持,提供五个新类别,分别是CHttpServer 、CHttpFilter  、CHttpServerContext 、CHttpFilterContext、CHtmlStream,用以建立交互式Web 应用程序。整合环境方面也对应地提供了一个ISAPI Extension Wizard 。在附加价值上,Visual C++ 4.1 提供了GameSDK,帮助开发Windows 95 上的高效率游戏软件。Visual C++ 4.1 还提供不少个由协力公司完成的OLE 控制组件(OCXs),这些OLE 控制组件技术很快就要全面由桌上跃到网上,称为ActiveX 控制组件。不过,遗憾的是,Visual C++ 4.1 的编译器有些臭虫,不能够制作VxD (虚拟装置驱动程序)。


1996 年下半年推出的MFC 4.2,提供对ActiveX 更多的技术支持,并整合Standard C++Library 。它封包一组新的Win32 Internet 类别(统称为WinInet),使Internet上的程式开发更容易。它提供22个新类别和40个以上的新成员函数。它也提供一些控制元件,可以绑定(binding)近端和远程的资料源(data sources)。整合环境方面,Visual C++4.2 提供新的Wizard 给ActiveX 程序开发使用,改善了影像编辑器,使它能够处理在Web 服务器上的两个标准图档格式:GIF  和JPEG。


1997 年五月推出的Visual C++ 5.0,主要诉求在编译器的速度改善,并将Visual C++  合并到微软整个Visual Tools 的终极管理软件Visual Studio 97  之中。所有的微软虚拟开发工具,包括Visual C++、Visual Basic 、Visual J++、Visual InterDev、Visual FoxPro、都在Visual Studio 97  的整合之下有更密切的彼此奥援。至于程序设计方面,MFC 本身没有什么变化(4.21 版),但附了一个ATL(Active Template Library )2.1 版,使ActiveX控制组件的开发更轻松些。


我想你会发现,微软正不断地为「为什么要使用MFC」加上各式各样的强烈理由,并强烈导引它成为Windows 程序设计的C++ 标准接口。你会看到愈来愈多的MFC/C++ 程式码。对于绝大多数的技术人员而言,Application Framework的抉择之道无它,「MFC是微软公司钦定产品」,这个理由就很呛人了。



纵览MFC


MFC 非常巨大(其它application framework 也不差),在下一章正式使用它之前,让我们先做个浏览。



MFC 类别主要可分为下列数大群组:


■General Purpose classes -   提供字符串类别、数据处理类别(如数组与串行),异常情况处理类别、文件类别... 等等。


■Windows API classes -  用来封包Windows API ,例如窗口类别、对话框类别、DC 类别... 等等。


■Application framework classes -  组成应用程序骨干者,即此组类别,包括Document/Vie w 、消息邦浦、消息映射、消息  绕行、动态生成、文件读写等等。


■high level abstractions -  包括工具栏、状态列、分裂窗口、卷动窗口等等。


■operation system extensions -   包括OLE 、ODBC 、DAO、MAPI 、WinSock、ISAPI等等。



General Purpose classes


也许你使用MFC 的第一个目标是为了写Windows 程序,但并不是整个MFC 都只为此目的而活。下面这些类别适用于Windows,也适用于DOS。


CObject


绝大部份类别库,往往以一个或两个类别,做为其它绝大部份类别的基础。MFC 亦复如此。CObject 是万类之首,凡类别衍生自CObject 者,得以继承数个对象导向重要性质,包括RTTI(执行时期型别鉴识)、Persistence(对象保存)、Dynamic Creation(动态生成)、Diagnostic(错误诊断)。本书第3章对于这些技术已有了一份DOS 环境下的模拟,第8章另有MFC 相关源代码的探讨。其中,「对象保存」又牵扯到CArchive ,「诊断」又牵扯到CDumpContext,「执行时期型别鉴识」以及「动态生成」又牵扯到CRuntimeClass。


数据处理类别(collection classes )


所谓collection ,意指用来管理一「群」对象或标准类型的资料。这些类别像是Array 或List  或Map 等等,都内含针对元素的「加入」或「删除」或「巡访」等成员函数。Array(数组)和List(串行)是数据结构这门课程的重头戏,大家比较熟知,Map (可视之为表格)则是由成双成对的两两对象所构成,使你很容易由某一对象得知成对的另一物件;换句话说一个对象是另一个对象的键值(key )。例如,你可以使用String-to-StringMap ,管理一个「电话-人名」数据库;或者使用Word-to-Ptr Map,以16 位数值做为一个指针的键值。


最令人侧目的是,由于这些类别都支持Serialization ,一整个数组或串行或表格可以单一一进程序代码就写到文件中(或从文件读出)。第8章的Scribble Step1  范例程序中你就会看到它的便利。


MFC 支持的collection classes 有:


杂项类别


■CRect-封装Windows 的RECT  结构。这个类别在Windows 环境中特别有用,因为CRect 常常被用作MFC 类别成员函数的参数。


■CSize-封装Windows 的SIZE 结构。


■CPoint-封装Windows 的POINT  结构。这个类别在Windows 环境中特别有用,


因为CPoint 常常被用作MFC 类别成员函数的参数。


■   CTime  -  表现绝对时间,提供许多成员函数,包括取得目前时间(staticGetCurrentTime)、将时间资料格式化、抽取特定字段(时、分、秒)等等。它对于+ 、-、+=、-+ 等运算子都做了多载动作。


■   CTimeSpan  -  以秒数表现时间,通常用于计时码表。提供许多成员函数,包括把秒数转换为日、时、分、秒等等。


■   CString -  用来处理字符串。支持标准的运算子如= 、+=、<  和> 。


异常处理类别(exception handling classes )


所谓异常情况(exception),是发生在你的程序执行时期的不正常情况,像是文件打不开、内存不足、写入失败等等等。我曾经在第2章最后面介绍过异常处理的观念及相关的MFC 类别,并在第4章「Exception Handling 」一节介绍过一个简单的例子。与「异常处理」有关的MFC 类别一共有以下11 种:



Windows API classes


这是MFC 声名最著的一群类别。如果你去看看源代码,就会看到这些类别的成员函数所对应的各个Windows API 函数。


■   CWinThread -  代表MFC 程序中的一个执行线程。自从3.0 版之后,所有的MFC类别就都已经是thread-safe  了。SDK 程序中标准的消息循环已经被封装在此一类别之中(你会在第6章看到我如何把这一部份开膛剖肚)。
■   CWinApp -  代表你的整个MFC 应用程序。此类别衍生自CWinThread;要知道,任何32 位Windows 程序至少由一个执行线程构成。CWinApp 内含有用的成员变量如m _szExeName,放置执行档档名,以及有用的成员函数如ProcessShellComman d,处理命令列选项。

■   CWnd  -  所有窗口,不论是主框窗口、子框窗口、对话框、控制组件、view 视窗,都有一个对应的C++  类别,你可以想象「窗口handle」和「C++  对象」结盟。这些C++  类别统统衍生自CWnd,也就是说,凡衍生自CWnd  之类别才能收到WM_  窗口消息(WM_COMMAND 除外)。所谓「窗口handle」和「C++  对象」结盟,实际上是CWnd  对象有一个成员变数m _hWnd,就放着对应的窗口handle。所以,只要你手上有一个CWnd  对象或CWnd  对象指针,就可以轻易获得其窗口handle:HWND hWnd = pWnd->m_hWnd;
■   CCmdTarget -  CWnd  的父类别。衍生自它,类别才能够处理命令消息WM_COMMAND。这个类别是消息映射以及命令消息绕行的大部份关键,我将在第9章推敲这两大神秘技术。
■  GDI 类别、DC 类别、Menu 类别。



Application framework classes


这一部份最为人认知的便是Document/View,这也是使MFC 跻身application framework的关键。Document/View  的观念是希望把资料的本体,和资料的显像分开处理。由于文件产生之际,必须动态生成Document/View/Frame 三种对象,所以又必须有所谓的Document Template 管理之。


■   CDocTemplate、CSingleDocTemplate、CMultiDocTemplate - Document Template   扮演黏胶的角色,把Document  和View  和其Frame(外框窗口)胶黏在一块儿。


■   CSingleDocTemplate  一次只支持一种文件类型,CMultiDocTemplate 可同时支持多种文件类型。注意,这和MDI  程序或SDI  程序无关,换句话说,MDI  程序也可以使用CSingleDocTemplat e,SDI  程序也可以使用CMultiDocTemplate。




■   CDocument -  当你为自己的程序由CDocument 衍生出一个子类别后,应该在其中加上成员变量,以容纳文件资料;并加上成员函数,负责修改文件内容以及读写档。读写文件由虚拟函数Serialize 负责。第8章的Scribble Step1范例程序有极佳的示范。


■   CView  -  此类别负责将文件内容呈现到显示装置上:也许是屏幕,也许是打印机。文件内容的呈现由虚拟函数OnDraw  负责。由于这个类别实际上就是你在屏幕上所看到的窗口(外再罩一个外框窗口),所以它也负责使用者输入的第一线服务。例如第8章的Scribble Step1  范例,其View 类别便处理了鼠标的按键动作。



High level abstractions


视觉性UI 对象属于此类,例如工具栏CToolBar、状态列CStatusBar、对话框列CDialogBar 。加强型的View 也属此类,如可卷动的ScrollView、以对话框为基础的CFormView 、小型文字编辑器CEditView、树状结构的CTreeView,支持RTF文件格式的CRichEditView等等。


Afx 全域函数


还记得吧,C++ 并不是纯种的对象导向语言(SmallTalk和Java才是)。所以,MFC之中得以存在有不属于任何类别的全域函数,它们统统在函数名称开头冠以Afx。


下面是几个常见的Afx  全域函数:



MFC宏(macros)


CObject 和CRuntimeClass之中封装了数个所谓的object services ,包括「取得执行时期的类别信息」(RTTI)、Serialization(文件读写)、动态产生对象...等等。所有衍生自CObject的类别,都继承这些机能。我想你对这些名词及其代表的意义已经不再陌生--如果你没有错过第3章的「MFC 六大技术仿真」的话。


■   取得执行时期的类别信息(RTTI),使你能够决定一个执行时期的对象的类别信息,这样的能力在你需要对函数参数做一些额外的类型检验,或是当你要针对对象属于某种类别而做特别的动作时,份外有用。


■  Serialization   是指将对象内容写到文件中,或从文件中读出。如此一来对象的生命就可以在程序结束之后还延续下去,而在程序重新激活之后,再被读入。这样的对象可说是"persistent "(永续存在)。


■   所谓动态的对象生成(Dynamic object creation ),使你得以在执行时期产生一个特定的对象。例如document 、view 、和frame  对象就都必须支持动态对象生成,因为framework  需要在执行时期产生它们(第8章有更详细的说明)。


此外,OLE 常常需要在执行时期做对象的动态生成动作。例如一个OLE server  程序必须能够动态产生OLE items,用以反应OLE client 的需求。


MFC 针对上述这些机能,准备了一些宏,让程序能够很方便地继承并实作出上述四大机能。这些宏包括:



我也已经在第3章提过MFC 的消息映射(Message Mapping)与命令绕行(CommandRouting)两个特性。这两个性质系由以下这些MFC 宏完成:






MFC 数据类型(data types)


下面所列的这些数据类型,常常出现在MFC 之中。其中的绝大部份都和一般的Win32程序(SDK 程序)所用的相同。


下面这些是和Win32 程序(SDK 程序)共同使用的数据类型:





















原创粉丝点击