北京大学软件工程国家工程研究中心建设概要

上传人:ca****in 文档编号:121675982 上传时间:2022-07-19 格式:PPTX 页数:135 大小:1.47MB
返回 下载 相关 举报
北京大学软件工程国家工程研究中心建设概要_第1页
第1页 / 共135页
北京大学软件工程国家工程研究中心建设概要_第2页
第2页 / 共135页
北京大学软件工程国家工程研究中心建设概要_第3页
第3页 / 共135页
点击查看更多>>
资源描述
软件体系结构软件体系结构(Software Architecture)讲义九:软件框架构造技术及案例分析讲义九:软件框架构造技术及案例分析内内 容容1.软件框架概述2.软件框架研究现状3.实例研究San Francisco商业开发平台软件构造技术的发展软件构造技术的发展创造性的活动创造性的活动60年代,汇编语言结构化方法结构化方法70年代,面向功能,面向数据面向对象方法面向对象方法80年代,软件复用基于构件方法基于构件方法软件复用进一步发展软件复用成为软件构造技术的研究热点软件复用成为软件构造技术的研究热点软件复用技术(软件复用技术(1/2)软件复用是提高软件生产力和质量的一种技术,将已有软件的各种有关知识用于构造新的软件,以缩短软件开发和维护的花费代码级复用领域知识、开发经验、体系结构、需求、设计等的复用复用级别软件复用技术(软件复用技术(2/2)依据复用的组织方式 个别的(Ad-hoc)复用复用在个人 系统化的(Systematic)复用定义了复用过程和指南项目级别、特定领域抽象级别较高的产品复用 系统化复用对于提高软件的质量和生产率具有更大的作用,也有较大的风险软件框架概念的出现软件框架概念的出现 Smalltalk-80开发环境中的框架Model-View-Controller(MVC),被认为是第一个得到广泛应用的框架 Apple Inc.User Interface Framework 之后出现了一系列框架产品:Interview,ET+,Fire alarm system,(Taligent)CommonPoint,(IBM)San Francisco等等 许多学者,包括Johnson,Pree,Bosch等对框架,尤其是面向对象框架展开了大量研究,包括框架设计、框架实现、框架描述、框架复用、框架演化等软件框架的概念软件框架的概念 软件框架的定义和描述 定义1 一个框架由一组协作类组成,阐明了整个设计、类间依赖及成员类的责任分布。杨芙清,97 定义2 一个框架是有意义的相互协作的类的集合,它能够同时表达针对一个特定领域实现公共的需求和设计所需要的小尺度模式和主要机制。Firesmith,94 定义3 框架是一种微体系结构,为特定领域内的软件系统提供未完全实现的模板。Jacobson,Booch,99 定义4 框架是指一个部分完成的软件(子)系统,它将要被进一步实例化。框架定义了一个软件系统族的体系结构,并且提供了基本构造单元。框架同时定义了针对特定的功能,需要在哪里进行调整和修改。Buschmann,96 定义5 一个框架是一个类的集合,它体现了针对解决相关问题家族的抽象设计。Jacobson,Foot,88 定义6 一个应用框架,也称为类属应用(Generic applications),是为特定应用领域提供可复用结构的协作类集合。Gamma,95软件框架的概念软件框架的概念(续续)框架反映了一个领域内应用的软件体系结构,包括其组成成分、关系以及约束 框架同时定义了针对特定的功能需要在哪里进行调整和修改因此,软件框架 1.提供了创建具体应用的基本构造单元。2.是一个部分完成的软件(子)系统,它将要被进一步实例化。框架的分类框架的分类 框架的分类 根据应用范围分类 基础设施框架:GUI框架、语言处理框架 中间件集成框架:ORB框架、消息中间件 企业应用框架:San Francisco 根据复用方式分类 白盒框架:MFC 黑盒框架:Avalon项目框架的特性框架的特性部分实现部分实现逐步实现,逐步具体化DSSA 框架 应用DSSA是框架的高层设计,框架是抽象应用是框架的高层设计,框架是抽象应用框架的特性框架的特性“反向控制反向控制”Hollywood Principle:Dont call us.Well call you.框架的特性框架的特性固定点和扩展点固定点和扩展点 固定点 用户扩展和定制 扩展点 对于面向对象框对于面向对象框架而言,扩展点架而言,扩展点是抽象类是抽象类框架特性框架特性相关概念相关概念 领域工程 框架体现了特定领域的需求,抽象了特定领域中一组应用系统的共性,因此领域分析是一种得到领域知识的较理想的方法 产品线 应用框架是软件产品线核心资产库的重要组成部分,框架的设计和生产属于产品线核心资产库建设的范畴 构件库 从软件构造的角度来讲,框架是一种大粒度的构件。框架与构件库的区别 框架不仅仅是类的简单集合,而且定义了一个领域通用的高层设计 构件库的结构建立于构件分类基础之上,而框架则直接反映了问题域的结构相关概念相关概念 框架和体系结构 框架决定了应用系统的体系结构 一个框架可以被实例化成为多个应用系统,每个应用系统具有特定的体系结构,因此框架从框架使用的角度来看,框架和体系结构之间存在着1对多(1:N)的关系 从框架开发的角度来看,框架反映了一个领域的体系结构(DSSA),它是DSSA的一个实例,因此,DSSA和框架之间同样存在着1对多(1:N)的关系 从在软件开发过程中所起的作用而言,体系结构是软件的高层设计抽象,它有助于系统开发团队之间的交流 DSSA是可以视为“参考”体系结构,对于领域内应用系统体系结构的设计具有指导意义 而开发框架最重要的目的则是针对特定领域的设计和代码复用相关概念相关概念 应用体系结构、DSSAApplication(N)Architecture(N)DSSA(1)Framework111n实例化领域工程n1n1相关概念相关概念 框架和软件开发过程 框架在整个软件开发过程中属于资产库建设的范畴,是领域设计和领域实现的重要制品之一 基于框架的软件开发活动可以分为 框架的设计和开发框架开发阶段 基于框架定制应用系统框架使用阶段 框架演化和维护阶段 设计和开发一个框架成本高,但是通过复用带来的效益也更加显著 框架本身是可复用资产,也有助于实现扩展部分的复用相关概念相关概念 框架和设计模式 从粒度上看,设计模式要小于框架,一个框架可以包括多个设计模式,但是设计模式不可能包括框架 框架要比设计模式更加特化,框架总是与特定的应用领域相关,而通常设计模式更加普通,可以应用任何的应用领域 框架的设计、实现以及描述利用了设计模式相关概念相关概念 框架与变化性控制 框架体现了领域共性 通过扩展点支持变化性 应用程序框架构件构件构件构件构件构件构件领域不变部分可变部分内容内容1.软件框架概念2.软件框架构造技术3.实例研究San Francisco商业开发平台软件框架构造技术软件框架构造技术 软件框架的开发过程模型 开发过程中的相关技术研究 领域分析 扩展点设计 框架实现和测试 框架的描述 框架的测试和维护 框架的演化 白盒黑盒框架Visual Builder框架的开发框架的开发 软件框架的开发过程模型领域分析领域模型,DSSA,标识变化性捕获框架需求识别框架问题域内的扩展点和固定点框架设计框架SA设计,扩展点设计,固定点设计框架实现和测试框架文档化应用分析应用设计应用实现新的需求、需求变化或更好的领域理解框架文档框架文档领域分析领域分析共性和变化性共性和变化性 当在某个领域而不是单个系统考虑问题时,就会发现一些特性是领域中所有系统共同具有的,而其它特性只是个别系统具有 所有系统都具有的特性是该领域中系统的本质特性,体现为该领域中系统的共性 只是部分或者个别系统具有的特性则体现为领域中系统的变化性变化性分类变化性分类 时间上的变化性和空间上的变化性 时间上的变化性:产品随着时间的变化 解决产品的演化问题 空间上的变化性:产品家族中产品间的区别 解决产品的复用问题 问题域的变化性和解空间的变化性 问题域的变化性主要来自于业务领域、客户、用户对领域应用系统需求的变化 业务策略:实现什么功能?解空间的变化来自于系统设计、实现技术、系统运行环境的变化 实现机制:怎样实现功能?变化性分类(续)变化性分类(续)变化性模式 必须的(Mandatory)需求:所有现有系统都具有这类需求 可选的(Optional)需求:部分现有系统具有这类需求,并非全部系统都具有 多选一的(Alternative):只能从多个变化项选择其中一个满足需求,这些变化项存在互斥关系 多选多的(Multiple Parallel Variability):这些变化性之间不存在互斥的关系,可以同时存在 变化性维度 组织机构、数据、功能、过程问题域 实现技术解空间扩展点(扩展点(1/3)为什么需要扩展点 支持应用领域的变化性 提高框架的灵活性 提高框架的可复用性 什么是扩展点 扩展点是软件框架中针对应用需求的、支持适应性变更的的扩展机制 扩展点是定义良好的框架特性,可以通过特例化或者组装等扩展机制来满足特定应用的需求扩展点扩展点OOF 面向对象框架中主要使用以下技术实现扩展功能 继承 组合 委托 参数化 扩展点扩展点OOF(续续)模板方法(Template method):定义不变流程调用钩子方法实现共性的领域知识钩子方法(Hook method):定义变化的部分实现特定应用的特殊需求定义为抽象方法扩展点扩展点OOF(续续)元模式THhook1:1 Connection PatternTHhooks1:N Connection PatternTHhook1:1 Recursive Connection PatternTHhooks1:N Recursive Connection PatternTHhook1:1 Recursive Unification PatternTHhook1:N Recursive Unification PatternTHUnification Pattern扩展点扩展点CBF 构件接口调用 接口定义和实现的分离支持构件功能的特定行为、算法和实现 插件支持特定算法和行为的动态加载和执行 构件的参数化支持构件对事件和状态变化的响应扩展点扩展点CBF Socket Plug DoMethod1 Plug DoMethod2 Application component 构 件 Framework 角色/构件绑定 Abstract component Parameter binder Template Framework Component Parameter 插座插件模板抽象构件外观 Facade Framework Computational Component Computational Component 扩展点扩展点CBF 构件组装 参数化组装:运行参数、配置文件、脚本程序 消息机制:消息中间件 代理:桩方式、适配器、容器、Web Service机制扩展点扩展点CBF Framework Component Application Component Script Executer Script Interpreter Script Creator Script 消息的发送和接收 Message broker Framework component Application Component 应用构件 部署描述 服务器连接管理,安全性 事务管理 生命周期管理 通信管理 服务 注册器 服务接口规约 服务实现规约 查找 服务接口 服务请求者 生成 服务代理 服务 提供者 绑定 服务 查找 交互 活动 制品 注册 脚本消息机制Web Services容器小结小结OOF和和CBF的不同的不同 面向对象框架 机制:面向对象技术的多态和继承机制 复用方式:通过继承框架中的抽象类来完成特定行为的定制,白盒复用 问题:框架的过度增值、脆弱的基类和隐式体系结构 基于构件的框架 机制:构件接口调用、构件组装等 复用方式:通过一些集成机制得到对象或者构件的不同组装,来定义特定行为的,黑盒复用框架描述语言(框架描述语言(1/6)框架文档必须包含的内容 框架的目的 明确框架针对的问题域,以及框架为问题域的哪些问题提供了解决方案 如何使用框架 框架得到正确使用并发挥最优效果的关键所在 应用实例 阅读实例是理解框架主要结构的方法 框架使用者可以从一组实例中看出框架的边界和不足 框架的设计描述 表达框架的整体体系结构和扩展点的设计细节框架描述语言(框架描述语言(2/6)Cook Book途径 类似“菜谱”的、一步一步讲述如何使用框架 使用自然语言,举例说明框架的使用,易于理解 对框架设计的描述不充分 MVC Cook Book方法、MacApp Cook Book方法、Active Cook Book方法框架描述语言(框架描述语言(3/6)模式途径 主题(Motif)方法 每一个主题描述一个待解决的问题,给出不同的解决方案 适合描述框架如何被使用 面向对象设计模式方法 面向对象设计模式描述了部分的面向对象设计,并不适合表达一个面向对象框架的完整设计框架描述语言(框架描述语言(4/6)结构化语言途径 框架描述语言(FDL)类似于C+函数说明 形式化的框架实现语言以及实现模板 没有给出框架的设计描述 基于XML语言 比较全面地给出了框架中的关键实体、实体的性质以及实体之间的关系 对框架如何使用的描述不充分框架描述语言(框架描述语言(5/6)UML扩展途径UML-F 采用一系列布尔类型的标识值来描述面向对象框架中的三种变化点:可变方法、可扩展类和可扩展接口 variable标记值表示可变方法 extensible标记值表示可扩展类 dynamic和static标记值分别表示运行时配置或者非运行时配置的需求 appl-class标记值表明一个类是否特定于应用 incomplete用来表示可扩展接口 框架描述语言(框架描述语言(6/6)框架描述途径比较CookBook模式途径主题 OO模式框架描述语言XML语言途径ULMF框架的目的好好差差差差如何使用框架好好好一般一般好应用范例好好差好好差设计细节的表达差好好差一般好框架总体结构的表达差一般好差一般一般框架的测试(框架的测试(1)框架测试的主要目的是验证开发完成的框架是否满足领域分析阶段的需求 测试活动:单元测试:针对固定点 集成测试:框架是否覆盖了所针对的领域 构件之间的协作是否正确 框架扩展点实现是否正确 除了框架本身的测试,框架文档也是其中重要测试内容,需要验证框架文档是否正确的描述了框架扩展点框架的测试(框架的测试(2)由于框架是针对复用开发的软件制品,它并不是完整的应用系统,因此在进行测试时,需要采取以下策略:通过开发驱动模块调用框架接口,测试框架对外提供的功能 在进行集成测试时,最有效的措施就是在领域中选择一个有代表性的应用系统进行构造,测试基于框架能否完成目标系统,即框架的可复用性。从这个角度来看,框架的复用过程也是框架的测试过程,一个被复用多次的框架,其正确性将有显著提高框架的维护(框架的维护(1)框架维护首要的目标是通过改善框架结构,提高框架性能以及可复用性,即完善性维护,原因:框架作为一种可复用资产,内部错误比例将随着不断复用大大降低 框架是针对特定领域的,其设计已经考虑了变化性,具有较高的灵活性,可以通过框架扩展以实现需求的变化框架的维护(框架的维护(2)一系列重构(Refactoring)活动有助于实现框架的完善性维护,所谓重构,是指在不改变可观察行为的前提下,对软件内部结构的改变,目的是使它更易于理解并且能够更廉价地进行改变 针对面向对象的软件框架,Opd92OJ93中总结了三类高层的重构方式 抽象类重构:为具有一部分相同属性的类C1和C2创建一个抽象基类 子类重构:将一个复杂的类分解成几个小一点的具体类和一个表达抽象的基类 聚合类重构:识别聚积和部件 框架的演化(框架的演化(1/2)应用框架的演化过程模型 框架的演化(框架的演化(2/2)框架演化过程中需要考虑的问题:识别具有演化趋势的模块 识别框架各版本之间改动较多的模块,这些模块应该是下一个版本中最可能被重构的模块 确定框架发布的适当时间 避免由于已发布的产品不符合功能和质量需求而造成的不必要的维护费用 变化影响分析 框架的演化对下一个版本的影响和基于前一个版本开发的应用的影响,变化影响分析结果可用来预测框架演化带来的维护工作量 需求管理 预测增加新的需求的成本,决定是否在框架实例或新版本框架中加入新需求框架构造原则框架构造原则 单一责任原则 开放-封闭原则 Liskov替换原则 依赖倒置原则 接口隔离原则单一职责原则(单一职责原则(SRP)内容 就一个类而言,应该仅有一个引起 它变化的原因,这条原则被称为内聚性原则。一般地,内聚性是指一个模块组成元素之间的功能相关性。在本条原则中,把内聚性和引起一个模块或类的改变的作用联系起来。为了理解这一原则,首先要回答什么是职责?在SRP中,把职责定义为:引起变化的理由a reason of change)。根据这一定义,显然可知:如果能够想到多个(1)动机来改变一个类,那么这个类就具有多于一个的职责。实践中,人们很习惯以“组”的形式来考虑类的职责。例如:一个接口“调制解调器”有四个功能:interface modem public void dial(string pno);public void hangup();public void send(char c);public void recv();这显然违背了SRP原则!原因是,根据职责的定义,可以认为该接口有两个职责:连接处理 public void dial(string pno);public void hangup();数据通信 public void send(char c);public void recv();是否将这2个职责分离取决于应用程序变化的方式:如果应用程序的变化会影响连接函数的声明(signature),那么调用send和recv就必须重新编译,因此应分离这两种职责。如果应用程序的变化总是导致这两个职责同时变化,那么就不必分离这两种职责。耦合职责的分离 就上一个例子而言,可以把2个职责分离为:interfaceinterfaceData ChannalData Channal+send(:char)+send(:char)+recv():char+recv():charinterfaceinterfaceConnectionConnection+dial(pno:Stri+dial(pno:String)+hangup()ng)+hangup()Modem Modem ImplementationImplementation其中,可以把ModemImpiementation类看作是一个杂凑物(kludge),通过分离它们的接口,解耦了概念。所有的依赖关系都与ModemImpiementation类无关。除了main外,谁也不知道它的存在。持久化问题-左图给出了一种常见的违反该原则的情况 其中,类Employee包含了业务规则和持久性控制。这2个职责在多数情况下不应该合在一起。因为业务规则往往会不断的变化,并且变化的原因也各不相同。处理:1)测试驱动的开发实践,往往会避免这种情况发生,即迫使对这2种职责进行分离。2)如果出现了这种情况,可以使用FAADE和 PROXY模式对设计进行重构,分离这2种职责。Employee Employee+CalculatePay+CalculatePay+Store+StorePersistence Persistence SubsystemSubsystem 结论 SRP是最简单的一个原则,但也是最难运用的原则之一;在设计中,人们会自然地把职责合在一起;软件设计真正要做的许多内容,就是发现职责,并把这些职责相互分离。本质上,其它原则都是以这种或那种方式回答第3个结论:即分离职责。开放开放-封闭原则封闭原则(The Open-Closed Principle,OCP)两截门(Dutch Door)-一个被水平分割为两部分的门,这样的每一部分都可以独立保持开放或关闭。-美国英语传统字典,第4版,2000年 内容:软件实体(类、模块、函数等)应该是可扩展的,但是不可修改的。这一原则是Bertrand Meyer在1998年提出的。提出这一原则的背景之一:Ivar Jacobson曾经说过:“任何系统在其生存周期中都会 发生变化。如果期望开发的系统不会在第1版本后就被抛弃,必须牢牢记住这一点。”遵循这一原则开发的软件具有以下特点:“对于扩展是开放的”(open for extention)这意味着模块的行为是可以扩展的。换言之,可以改变模 块的功能。“对于改变是封闭的”(closed for modification)这意味着对模块行为改变时,不必改动模块的源代码或 二进制代码。模块的二进制可执行版本,无论是可链接的 库、DLL或Java的.jar文件,都无需改动。怎样才能做到看起来似乎矛盾的以上两点?关键的是抽象!不允许修改的模块,通常被认为是具有“固定”行为的模块。抽象基类以及可能的派生类,就能够描述一组任意可能行为的抽象体。模块可以操作一个抽象体。由于模块依赖一个“固定”的抽象体,因此它对于更改可以是封闭的;但通过该抽象体的派生,可以扩展该模块的行为。例如,ClientServerClientClient类是既不开放又不封闭的类类是既不开放又不封闭的类 (其中,其中,Client Client 类和类和ServerServer类类都是具体类)都是具体类)实现实现OCP的一种结构:的一种结构:Clientinterfaceinterface Client Client InterfaceInterfaceServerSTRATEGYSTRATEGY模式:既开放又封闭的模式:既开放又封闭的Client Client 其中,其中,ClientInterfaceClientInterface类是一个拥有抽象成员的抽象类。类是一个拥有抽象成员的抽象类。Client Client 类使类使用这个抽象类,但用这个抽象类,但Client Client 类的对象却使用类的对象却使用ServerServer类的派生类的对象。类的派生类的对象。因此,如果希望因此,如果希望Client Client 对象使用一个不同的服务器类,那么只需从对象使用一个不同的服务器类,那么只需从ClientInterfaceClientInterface类派生一个新的类,而无需对类派生一个新的类,而无需对Client Client 类进行任何改动。类进行任何改动。Client Client 类需要实现一些功能,可以使用类需要实现一些功能,可以使用ClientInterfaceClientInterface的抽象接口来的抽象接口来描述这些功能。描述这些功能。ClientInterfaceClientInterface的子类型可以以任何方式来实现这个的子类型可以以任何方式来实现这个接口。这样,就可以通过创建接口。这样,就可以通过创建ClientInterfaceClientInterface的新的子类型的方式来扩的新的子类型的方式来扩展、更改展、更改Client Client 中指定的行为。中指定的行为。实现实现OCP的另一结构:的另一结构:PolicyPolicy+PolicyFunction()+PolicyFunction()-ServiceFunction()-ServiceFunction()Implementation-ServiceFunction()-ServiceFunction()Template MethodTemplate Method模式:既开放又封闭的基类模式:既开放又封闭的基类 其中,其中,PolicyPolicy类具有一组实现了某种策略的共有函数。和上图中的类具有一组实现了某种策略的共有函数。和上图中的ClientClient类中的函数类似,这些策略函数使用一些抽象接口描述了一些要完成的功类中的函数类似,这些策略函数使用一些抽象接口描述了一些要完成的功能。不同的是,在这个结构中,这些抽象接口是能。不同的是,在这个结构中,这些抽象接口是PolicyPolicy 类的一部分。它类的一部分。它们在们在C+C+中表现为纯虚函数,在中表现为纯虚函数,在JavaJava中表现为抽象方法。这些函数在中表现为抽象方法。这些函数在PolicyPolicy的子类型中实现。这样,可以通过从的子类型中实现。这样,可以通过从PolicyPolicy类派生出新类的方式,类派生出新类的方式,对对PolicyPolicy中指定的行为进行扩展或更改。中指定的行为进行扩展或更改。以上两个模式是满足以上两个模式是满足OCPOCP原则最常用的方法。应用它们,可以把一个原则最常用的方法。应用它们,可以把一个功能的通用部分和实现细节清晰地分离开来。功能的通用部分和实现细节清晰地分离开来。结论 在许多方面,开发-封闭原则(OCP)都是面向对象设计的 核心。遵循这一原则,可以带来巨大好处-灵活性、可复用 性以及可维护性。不是使用了面向对象语言就是遵循了这一原则。对应用程序中的每一部分肆意地使用抽象,同样不是一个好的主意。正确的做法是,开发人员应该仅对呈现频繁变化的那些部分做出抽象。其中,“拒绝不成熟的抽象与抽象本身一样重要的”。Liskov替换原则替换原则(LSP)在C+和Java这类语言中,支持抽象和多态的关键机制是继承(inheritance)。正是使用了继承,才可能创建实现其基类中抽象方法中的派生类。是什么设计原则支配这种特殊的继承用法?最佳的继承层次的特征是什么?怎样的情况会使创建的类层次陷入不符合OCP?以上正是LSP原则要回答的问题。内容:子类型必须能够替换掉它们的基类型。这一原则是Barbara Liskov在1988年首先提出的。“若对每个类型S的对象o1,都存在一个类型T的对象o2,使得在所有针对编写的程序P中,用o1,替换o2后,程序P行为功能不变,则S是T的子类型。”若违反这一原则,会出现什么后果?例如:假定有一个函数f,它的参数指向某个基类B的“指针”或“引用”。同样,假定有B的某个派生类D,如果把D的对象作为B类型传递给f,就会导致f出现错误的行为。那么D就违反了LSP。显然,D对于f来说是脆弱的。违反 LSP,常常以违反OCP的方式使用运行时的类型辨别(RTTI)而导致的。这种方式往往是显式地使用一个if 语句或if/else来确定一个对象的类型,以便可以选择该类型的正确行为。考虑以下程序:struct Point double x,y;struct Shape enum ShapeType square,circle itsType;Shape(ShapeType t):itsType ;struct Circle:public Shape Circle():Shape(Circle);void Draw()const;Point itsCenter;double itsRadius;struct Square:public Shape Sqaure():Shape(Sqaure);void Draw()const;Point itsTopLeft;double itsSide;void DrawShape(const Shape&s)if(s.itsType=Shape:square)static_cast(s).Draw();else if(s.itsType=Shape:circle)static_cast(s).Draw();显然,该程序中的DrawShape函数违反了OCP 它必须知道Shape类所有的派生类,且每次创建一个Shape的派生类都必须要更改它。其原因是,Square类和Circle类是Shape的派生类,具有函数Draw(),但没有重写(override)Shape 中的函数。由于Square类和Circle类不能替换Shape,所以DrawShape函数必须检查输入的Shape对象,确定它的类型,继之调用函数Draw()。Square类和Circle类不能替换Shape,这违反了LSP,从而使DrawShape违反了OCP。还有其它一些方式,可以引发违反Liskov替换原则。例如:is A关系的使用-没有把子类中那些不具有多态性的函数声明为虚函数;基于契约设计的使用-派生类违反了有关基类的约定。在派生类的方法中填加了其基类不能割舍的异常 结论:LSP是使OCP成为可能的主要原因之一。正是子类型的可替换性,才使使用基类的模块在无须改变的情况下可以予以扩展。这种可替换性必须是开发人员可以隐式依赖的东西。因此如果没有显示地强制基类类型的契约,那么代码就必须良好地并显式地表达出这一点。“is-A”的含义过于宽泛,以至于不能作为子类型的定义。子类型的正确定义是“可替换性的”,这里的可替换性可以通过显式或隐式的契约予以定义。依赖倒置原则依赖倒置原则(DIP)内容:高层模块不应该依赖低层模块。二者都应该依赖抽象。抽象不应该依赖细节。细节应该依赖抽象。该原则是框架设计的核心原则 层次化 Booch曾经说过:“所有结构良好的面向对象构架都具有清晰的层次定义,每个层次通过一个定义良好的、受控的接口向外提供一组内聚的服务。”对以上这句话的简单理解,可能会出现以下结构:Policy LayerMechanism LayerUtility Layer这一结构存在一个潜伏的错误特征这一结构存在一个潜伏的错误特征:(1 1)Policy layerPolicy layer对于其下一直到对于其下一直到 Utility LayerUtility Layer的改动,都的改动,都 是敏感的。是敏感的。(2 2)这种依赖是可传递的。)这种依赖是可传递的。-结论:这一结构是不好的!结论:这一结构是不好的!合适的模型应该是:PolicyPolicyMechanism Mechanism UtilityUtilityPolicPolicy y LayerLayerinterfaceinterfacePolicy Policy Service Service InterfaceInterfaceMechanism Mechanism LayerLayerinterfaceinterface Mechanism Service Mechanism Service InterfaceInterfaceUtiliUtility ty LayerLayer 每个较高层次为它所每个较高层次为它所需要的服务声明一个抽需要的服务声明一个抽象接口,较低层次实现象接口,较低层次实现这些抽象接口;这些抽象接口;每个较高层次都通过每个较高层次都通过抽象接口使用下一层。抽象接口使用下一层。这样这样1 1)高层就不依赖低层,)高层就不依赖低层,而低层则依赖高层;而低层则依赖高层;2 2)不仅解除了其中的)不仅解除了其中的传递依赖关系,而且还传递依赖关系,而且还解除了高层与其它层的解除了高层与其它层的依赖关系。依赖关系。倒置的接口所有权问题 这就是著名的Hollywood 原则“Dont call us,well call you.”即低层模块实现了在高层模块中声明并被高层模块调用的接口。依赖于抽象 这是解释DIP规则的一个启发式规则。该规则建议不应该依赖具体类-即程序中的所有依赖关系都应该终止于抽象类或接口。根据这个启发式规则,可知:任何变量都不应该持有一个指向具体类的指针或引用;任何类都不应该从具体类派生;任何方法都不应该覆写它的任何基类中已实现的方法。注意:在编程中,有时必须要创建具体类的实例,而创建这些实例的模块将会依赖它们。这说明程序中一般都会出现违反启发式规则的情况。如果一个具体类不太会改变,且不会创建其它类似的派生类,那么依赖它也不会造成损害。这说明对那些稳定的具体类而言,启发式规则似乎不大合理。如果具体类是不稳定的,且还不想直接依赖之,则可以把它们隐藏在抽象接口之后,以隔离它们的不稳定性。依赖倒置规则可应用于任何存在一个类向另一个类发送消息的地方。违反依赖倒置原则的例子:ButtonButton+poll()poll()LampLamp+turnOn()+turnOn()+turnOff()turnOff()这是一个以这是一个以ButtonButton控制控制LampLamp的系统。的系统。其中,其中,ButtonButton类直接依类直接依赖赖LampLamp对象,这个设计对象,这个设计不能让不能让ButtonButton控制其它控制其它设备。设备。该设计方案就违反了该设计方案就违反了DIPDIP,即应用程序的高即应用程序的高层策略没有与低层策略层策略没有与低层策略相分离,自然使抽象依相分离,自然使抽象依赖于具体细节。赖于具体细节。其对应的其对应的JavaJava如左所示。如左所示。什么是高层策略?它是应用的抽象,是那些不随具体细节而改变的“真理”。它是系统内部的系统-隐喻(metaphore)ButtonButton+poll()poll()interfaceinterfaceButtonServerButtonServer+turnOn()turnOn()+turnOff()+turnOff()Lamp Lamp通过倒置对通过倒置对LampLamp的依赖关系,可以形成以上的设计。的依赖关系,可以形成以上的设计。其中,由接口其中,由接口ButtonServerButtonServer提供一些抽象方法,提供一些抽象方法,ButtonButton可以使用这些可以使用这些方法对有关设备进行方法对有关设备进行控制。由控制。由LampLamp来实现接口来实现接口ButtonServerButtonServer。这样的设计就具有很好的灵活性。但问题是这样的设计就具有很好的灵活性。但问题是LampLamp可能还受其他类的控可能还受其他类的控制。但由于制。但由于LampLamp实现了接口实现了接口ButtonServerButtonServer,所以就做不到这一点。所以就做不到这一点。结论:使用传统的过程化设计所创建的依赖关系结构,策略是依赖于细节的。这样会使策略受到细节改变的影响。面向对象程序设计倒置了依赖关系的结构,是策略和细节都依赖抽象,并且通常是客户的服务接口。这种依赖关系的倒置,正好是面向对象的标志所在。依赖倒置原则是实现许多面向对象技术所宣称的那些益处的低层机制。它的正确应用对创建可复用的框架是必须的。同时对建造具有弹性的代码(应对变化)是非常重要的。应用该原则可以做到抽象和细节彼此分离,因此代码也易于维护。接口隔离原则接口隔离原则(ISP)内容:不应强迫客户(client)依赖它们不用的方法。解决的问题:ISP原则用来处理“胖接口”所带来的缺点。何谓胖接口?如果类的接口不是内聚的,则称该接口是胖接口。换言之,类的胖接口可以分解为多组方法,每一组方法服务于一组不同客户程序。接口污染问题 考虑一个安全系统。其中有一些Door对象,可以加锁和解锁,并且知道自己所处的状态(开/关)。class Door public:virtual void Lock()=0;virtual void UnLock()=0;virtual bool IsDoorOpen()=0;显然,这是一个抽象类。客户程序可以使用符合Door的那些接口对象,而不依赖Door的特定实现。现在考虑这样一个实现-TimedDoor.其中,如果门开着的时间过长,就会发出警报。为此,TimedDoor对象需要和一个名为Timer的对象进行交互。即如果希望得到超时时间,就可以调用Timer的Register函数,该函数有2个参数:一个是超时时间,另一个是TimerClient对象的指针,该对象的TimeOut函数会在达到超时时予以调用。现在的问题是,如何建立类TimerClient和类TimedDoor之间的关联,才能在超时时通知TimedDoor中相应的处理代码?下面给出了一种可想到的方案:TimerDoorTimedDoorInterface Timer Client+Timeout0.*其中,其中,DoorDoor继承了继承了Timer ClientTimer Client,因此因此TimedDoorTimedDoor也继承了也继承了Timer ClientTimer Client,这就可以保证这就可以保证TimerClientTimerClient把自己注把自己注册到册到TimerTimer中,并可接收中,并可接收TimeOutTimeOut的消的消息。息。现在的问题是,如何建立类现在的问题是,如何建立类TimerClientTimerClient和类和类TimedDoorTimedDoor之间之间的关联,才能在超时时通知的关联,才能在超时时通知TimedDoorTimedDoor中相应的处理代码?中相应的处理代码?下面给出了一种可想到的方案:下面给出了一种可想到的方案:TimerInterface Timer Client+TimeoutDoorTimedDoor0.*其中,其中,DoorDoor继承了继承了Timer ClientTimer Client,因此因此TimedDoorTimedDoor也继承了也继承了Timer ClientTimer Client,这就可以保证这就可以保证TimerClientTimerClient把自己注把自己注册到册到TimerTimer中,并可接收中,并可接收TimeOutTimeOut的消的消息。息。现在现在,类类DoorDoor依赖于依赖于TimerClientTimerClient。该方案的主要问题就出现该方案的主要问题就出现在这里。在这里。1 1)不是所有种类的)不是所有种类的DoorDoor都需要定时功能。最初的都需要定时功能。最初的DoorDoor与定与定时功能没有任何关系,如果需要创建一个没有定时功能的派生时功能没有任何关系,如果需要创建一个没有定时功能的派生类,那么就必须要提供类,那么就必须要提供TimeOutTimeOut方法方法的的“退化退化”实现,这就违反实现,这就违反了接口分离原则。了接口分离原则。2 2)另外,使用这些派生类的应用程序,即使不使用定义的)另外,使用这些派生类的应用程序,即使不使用定义的TimerClientTimerClient,也必须引入之,因此就具有不必要的复杂性和不,也必须引入之,因此就具有不必要的复杂性和不必要的重复必要的重复-“臭味臭味”。这是一个接口污染问题:这是一个接口污染问题:1 1)DoorDoor的接口被一个它不需要的方法污染了的接口被一个它不需要的方法污染了-在在DoorDoor的接的接口中加入这个方法只是为了给它的子类带来好处。口中加入这个方法只是为了给它的子类带来好处。2 2)如果这样持续下去的话,每一次子类需要一个新方法时,)如果这样持续下去的话,每一次子类需要一个新方法时,就被加入到基类中,这样就可能进一步污染了接口,使它就被加入到基类中,这样就可能进一步污染了接口,使它“胖胖”了起来。了起来。3 3、实现分离接口的途径、实现分离接口的途径 1 1)分离客户(程序)就是分离接口)分离客户(程序)就是分离接口 Door Door的接口和的接口和TimerClientTimerClient的接口完全被不同的客户程序所使用,的接口完全被不同的客户程序所使用,即即TimerTimer使用使用TimerClientTimerClient,而对而对DoorDoor的操作使用了类的操作使用了类DoorDoor。既然客户程序是分离的,所以接口也应该保持分离。原因是既然客户程序是分离的,所以接口也应该保持分离。原因是客户程序对它们使用的接口是有影响的。客户程序对它们使用的接口是有影响的。2 2)使用委托)使用委托 分离接口分离接口 创建一个由创建一个由TimerClient TimerClient 所派生的对象,并把该对象的请求委所派生的对象,并把该对象的请求委托给托给TimedDoor.TimedDoor.TimerInterface Timer Client+TimeoutDoorTimedDoor+DoorTimeOut0.*Door Timer Adapter+Timeout()creates其中其中,当当TimedDoorTimedDoor想想要向要向TimerTimer对象注册一对象注册一个超时请求时个超时请求时,它就创它就创建一个建一个DoorTimerAdapter,DoorTimerAdapter,并并把它注册给把它注册给Timer.Timer.当当TimerTimer对象发送对象发送TimeoutTimeout消息给消息给DoorTimerAdapterDoorTimerAdapter时时,DoorTimerAdapterDoorTimerAdapter把把这个消息委托给这个消息委托给TimedDoor.TimedDoor.对这一方案的分析对这一方案的分析:1)1)该方案遵循了该方案遵循了ISP,ISP,并避免了并避免了DoorDoor的客户程序和之间的耦合的客户程序和之间的耦合.2)2)即使对即使对TimerTimer的进行了修改的进行了修改,也不会影响也不会影响DoorDoor的使用者的使用者.其中其中TimerTimer的定义如下的定义如下:Class TimerClass Timer public:public:void Register(int timeout,int timeoutID,TimeCclient void Register(int timeout,int timeoutID,TimeCclient*client);client);Class TimerClient Class TimerClient public:public:virtual void TimeOut(int timeoutID)=0;virtual void TimeOut(int timeoutID)=0;3)Timed Door3)Timed Door也不必具有和也不必具有和 TimerClientTimerClient一样的接口一样的接口;4)4)DoorTimerAdapterDoorTimerAdapter会将会将TimerClientTimerClient接口转换为接口转换为TimedDoorTimedDoor 接口接口.因此,这是一个非常通用的解决方案。因此,这是一个非常通用的解决方案。5)5)该方案尽管是一种通用的该方案尽管是一种通用的,但不是很优雅的但不是很优雅的.即每次想去注即每次想去注 册一个超时请求时册一个超时请求时,都要创建一个新的对象都要创建一个新的对象.这对于那些对这对于那些对 内存和运行时间要求高的系统而言内存和运行时间要求高的系统而言,例如嵌入式实时系统例如嵌入式实时系统,就显得不够理想。就显得不够理想。3 3)使用多继承)使用多继承 分离接口分离接口下图给出使用多继承并达到遵循下图给出使用多继承并达到遵循ISPISP的方案的方案:TimerInterface Timer Client+TimeoutDoorTimedDoor+DoorTimeOut0.*其中其中,在这个模型中在这个模型中,TimedDoorTimedDoor同时继承了同时继承了DoorDoor和和TimerClient.TimerClient.这样这样,尽管这尽管这2 2个基类个基类的客户程序都可以使的客户程序都可以使用用TimedDoor,TimedDoor,但在实但在实际上却都不再依赖际上却都不再依赖TimedDoor.TimedDoor.从而从而,它们它们就通过分离的接口使就通过分离的接口使用同一对象用同一对象.比较比较:就这一问题的就这一问题的2),3)2),3)方案而言方案而言,只有当只有当Door Timer AdapterDoor Timer Adapter对象所做的转换是对象所做的转换是必须的必须的,或不同时候回需要不同转换时或不同时候回需要不同转换时,才会选择才会选择2)2)中给出的方案中给出的方案.结论结论 1 1、胖类可以导致它们的客户程序之间产生不正常的、且有胖类可以导致它们的客户程序之间产生不正常的、且有害的耦合关系。当一个客户程序要求该胖类进行一个修改时,害的耦合关系。当一个客户程序要求该胖类进行一个修改时,会影响到其他所有客户程序。因此,客户程序应该仅仅依赖它会影响到其他所有客户程序。因此,客户程序应该仅仅依赖它们实际调用的方法。们实际调用的方法。2 2、把胖类的接口分解为多个特定于客户程序的接口,可以、把胖类的接口分解为多个特定于客户程序的接口,可以实现以上目标。每个特定于客户程序的接口仅仅声明它的特定实现以上目标。每个特定于客户程序的接口仅仅声明它的特定客户或客户组调用的那些函数,接着该胖类就可以继承所有特客户或客户组调用的那些函数,接着该胖类就可以继承所有特定于客户程序的接口,并实现它们。这就解除了客户程序和它定于客户程序的接口,并实现它们。这就解除了客户程序和它们没有调用的方法之间的依赖关系,并使客户程序之间互不依们没有调用的方法之间的依赖关系,并使客户程序之间互不依赖。赖。小结:框架技术带来的好处小结:框架技术带来的好处 在应用系统开发中使用框架 减少应用软件上市的时间 提高应用系统的可靠性、易维护性和易测试性 框架体现了专家的意见,因为框架是针对一个领域的需求开发的,领域专家的知识体现于框架中 建立软件标准,良好设计的框架为一个公司的应用开发,形成软件生产线确立了标准 框架提高了应用软件的一致性和兼容性,易于集成并且具有一致的用户界面内内 容容1.软件框架概述2.软件框架研究现状3.实例研究San Francisco商业开发平台San Francisco 背景背景 San Francisco(简称SF)是IBM网络领域解决方案系列产品中的战略性产品 它是一个基于Java的构件集,使得开发者不再从最底层开始构造商业应用系统,而是利用已经有的构件对服务器端的商业应用系统进行开发 同时,应用系统只需要一次开发就可以在包括Windows NT、OS/400、AIX、Solaris、HP-UX以及Reliant UNIX在内的平台上运行目目 标标 目标1:为商业应用领域提供一个合理的、完整的模型,提供定义良好的编程模型,使得没有面向对象技能的应用提供商可以有效使用OO技术 提供领域公共的可复用资产 为框架的演化使用提供支持 可扩展性和可修改性较强的构件 提供灵活的持久性对象存储方案 为SF框架使用者提供集成的工具目目 标标 目标二:提高企业的竞争力,确保企业使用框架可以提高应用软件的生产率和产品质量 好的面向对象设计可修改性和可扩展性 支持client/server或者其分布式模型 用户界面和业务对象的分离 业务对象、业务策略和业务逻辑的分离 其它构件的集成 目标三:提供一个开放的解决方案,以确保框架使用者在操作系统、硬件环境以及应用体系结构方面有较大的选择范围SF体系结构的特点体系结构的特点 分布式 一个分布式对象基础设施(distributed object infrastructure)一组商业应用构件(a set of application business components)面向对象技术 封装了复杂的变化性,使得应用系统可以使得应用可以很容易得随着需求的变化而改变,更易于维护和演化 跨平台 通过JAVA的虚拟机,SF实现了与操作系统隔离,获得平台独立性 商业应用框架 商用应用框架是一些代表商业实体的类,它们相互协作实现核心商业过程。面向对象框架的利用允许商业管理系统的开发者依赖一个已存在的商业过程和商业对象。为此,开发者能够集中精力完成最终的不同需求SF体系结构(体系结构(1)SF体系结构(体系结构(2)SF是一个多层的、共享的、灵活的系统,用于开发独立于平台的、分布式面向对象的商业应用系统。完整的SF框架由三个不同的层次组成:基础层(Foundation),提供构造分布的、面向对象的、多平台的应用系统所需的基础设施和服务 通用商业对象层(Common Business Objects,简称CBOs),提供通
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 商业管理 > 销售管理


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!