null第9章 面向对象设计第9章 面向对象设计面向对象的设计原则
系统设计
对象设计
设计模式
RUP的设计活动
RUP的实现活动
9.1 面向对象的设计概念及原则9.1 面向对象的设计概念及原则 1、有关概念
面向对象设计将面向对象分析创建的分析模型变换为设计模型,它将作为软件构造的蓝图。但由于面向对象分析与设计活动是一个迭代与演化的过程,概念与表示方法的一致性使得分析与设计阶段平滑过渡。
传统的设计方法将问题域分解成一系列任务来完成,这些任务形成过程式软件的基本结构。面向对象方法把问题域作为一系列相互作用的对象,在此基础上构造出基于对象的软件系统结构。
面向对象设计包括系统设计和对象设计。系统设计包括如何把整个系统分解为子系统、子系统的软硬件布局等策略性决策;对象设计是根据具体的实现策略,对分析模型进行扩充。通过系统设计和对象设计产生设计模型,是进一步完成系统实现的基础。下表列出了分析模型与设计模型的区别:null 分析模型 设计模型
概念模型,回避了实现问题; 物理模型,是实现蓝图 ;
对设计是通用的; 针对特定的实现;
对类型有3种构造型; 对类型有任意数量的构造型
(依赖于实现语言);
不太形式化 ; 比较形式化;
开发费用较低; 开发费用较高;
层数少; 层数多;
动态的; 动态的(特别关注时序);
勾画系统的设计轮廓; 进行系统设计;
主要通过研讨会等方式创建; 设计模型和实现模型需双向
开发;
可能不需要在整个生命周期 在整个生命周期内都应该维护
内都做维护;
null 2、OO设计原则
(1)封装
是将一个完整的概念组成一个独立的单元,然后通过一个名字来引用它。在OO系统的较高层次,将一些相关的应用问题封装在一个子系统中,对子系统的访问是通过访问子系统的接口实现的;在较低的层次将具体对象的属性和操作封装在一个对象类中,通过类的接口访问其属性。
(2)抽象
OO方法不仅支持过程抽象还支持数据抽象。类封装了数据和操作数据的方法,类是一种包含过程抽象的数据抽象,它对外提供的公共数据接口构成了类的规格说明(类的协议)。使用者无需知道类中的具体操作是如何实现的,无需了解内部数据的具体表现方式,只要搞清它的规格说明,就可通过接口定义的操作访问类的数据。null (3)信息隐蔽
信息隐蔽是通过对象的封装实现的。类的结构分离了接口和实现,对于类的使用者来说,属性的表示和操作的实现都是隐蔽的。
(4)强内聚
• 服务内聚: 一个服务完成且仅完成一个功能。
• 类内聚: 一个类的属性和操作全部都是完成某个任务所必须的,其中不包括无用的属性和操作。
• 层内聚: 把向用户或高层提供相关服务的功能放在一起,而将其他内容排除在外。为了保证适当的层内聚,往往有严格的层次结构,高层能够访问低层的服务,而低层却不能访问高层的服务(下图描述了这种关系)。
以下的相关服务可以放在同一层:计算服务、消息或数据传输服务、数据存储服务、管理安全服务、用户交互服务、访问操作系统服务、硬件交互服务等。•null用户界面应用逻辑访问操作系统访问数据库网络通信应用程序的典型层次处理应用协议处理连接处理包传输和接收通信系统中的简化层次null 层向外界提供服务的过程和方法通常称为应用编程接口(Application Programming Interface, API)。API的规格说明必须描述高层用来访问服务的协议,还要描述每个服务的语义和副作用。层内聚的优点如下:
• 替换高层模块对低层模块没有影响。
• 可以用等价的层替换低层,但必须复制该层所有的API,这样高层才不受影响。
其他有关传统方法中的功能内聚、通信内聚、顺序内聚、时间内聚等概念及提高内聚的原则在OO设计中仍然适用。
null (5)弱耦合
OO设计中,耦合主要指不同对象(包括类、包)之间相互关联的程度,如果一个对象过多地依赖于其它对象来完成自己的工作,不仅使系统的可理解性下降,还会增加测试、修改的难度,同时降低了类的可复用性和可移植性。但对象不可能完全孤立,当两个对象必须相互联系时,只通过类的公共接口实现耦合,不应该依赖于类的具体实现细节。
设计时尽量减少对象之间发送的消息数(Meyer建议的少接口),减少消息中的参数个数(小接口),对象之间以明显和直接的方式通信,减少通信的复杂程度(显式的接口)。传统方法中有关降低耦合的原则在OO方法中仍然适用。
null (6)可复用
为了提高工作效率、减少错误、降低成本,就要充分考虑软件的复用性。复用有两个方面的含义:一是尽量使用已有的类,包括开发环境提供的类库和已有的相似类。二是创建新类时考虑将来的可复用性。
类有三种复用方式:
• 实例复用
由于类的封装特性,使用者不需要了解内部的实现细节就可用适当的构造函数创建需要的实例,然后向所创建的实例发送适当的消息,启动相应的服务,完成需要的任务。
设计一个可复用性好的类是一件很困难的事情,因为,类提供的服务太多,会增加接口的复杂度,降低类的可理解性;提供的服务太少,则可能会降低复用性。在设计时,需要根据具体的应用环境和以往的经验来综合考虑,设计出合适的类构件。
null • 继承复用
当已有的类构件不能通过实例复用满足要求时,可以通过继承复用对已有的类构件进行修改,使它满足要求。在设计时,关键是要设计一个合理的、具有一定深度的类构件的继承层次结构。每个子类在继承父类的属性和服务的基础上,加入少量的新属性和新服务,这样做的好处是父子类的耦合度比较适当,接口简单,易于理解。
• 多态复用
多态是一种特性,这种特性使得一个属性或变量在不同的时期可以表示不同的对象。利用多态性可以使对象的对外接口更加一般化,系统运行时,根据接收消息的对象类型,由多态机制启动正确的方法,响应一个一般化的消息。null 例如出现下列情况:
• 操作与数据结构大小有关。
• 操作与外部设备特性有关。
• 实现算法将来可能会改进。
为了克服与表示方法、数据结构或硬件特点相关的操作给复用带来的困难,可以设计一个基类把与上述操作有关的服务定义为纯虚函数,然后在复用时先派生出一个新类,在新类中重新定义上述操作的算法。
设计一个可复用的软件比设计一个普通软件的代价要高,但随着这些软件被复用的次数的次数的增加,分摊到它的设计和实现成本就会降低。
null (7)简洁化设计
一个软件60%的工作量是维护工作。为了便于维护,现代软件工程越来越重视软件的简洁和易于理解。做好以下几点:
• 设计简单的类。避免定义太多的属性和服务。一个类的职责要清晰,易于理解也有助于复用。
• 使用简单的协议。对象之间的关联是通过消息触发的,消息过于复杂,说明对象之间的耦合程度太紧,不利于维护。
• 设计结果简洁明了。设计结果(如文档)描述用词准确、清晰、容易理解。9.2 系统设计9.2 系统设计 和传统设计的目的相同,是为实现系统需求而对软件体系结构进行的设计。系统设计过程包括以下活动:
• 划分分析模型为子系统。
• 标识问题的并发性。
• 选择软件体系结构的风格并分配子系统到处理器。
• 设计用户界面。
• 选择实现数据管理的基本策略。
• 标识全局资源及访问它们所需的控制机制。
• 为系统定义合适的控制流机制。
• 考虑边界条件。
• 评审并考虑权衡。null 1、划分分析模型
以定义类、关系和行为的内聚集合,将这些设计元素包装为子系统。
定义子系统时应该遵循以下
标准
excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载
:
• 子系统应该具有定义良好的接口,通过接口和系统的其余部分通信。
• 除了少数的“通信类”,在子系统中的类只和该子系统中的其他类协作。
• 子系统的数量不应太多。
• 子系统可以内部划分以降低复杂性。
null 当两个子系统互相通信时,可建立客户/服务器(C/S)结构或对等结构(P2P)。在C/S结构中,每个子系统只承担一个由客户端或服务器端隐含的角色,服务只是单向地从服务器端流向客户端;在P2P结构中,服务可以双向流动。
在划分子系统时,往往进行分层设计。系统的每一层包含一个或多个子系统,表示了完成系统功能所需的功能性的不同抽象层次。抽象级别由与其相关的处理对用户的可见程度来确定。(如
ppt
关于艾滋病ppt课件精益管理ppt下载地图下载ppt可编辑假如ppt教学课件下载triz基础知识ppt
第6页应用程序的典型层次结构)。
Buschmann及其同事提出以下分层设计方法:
• 建立分层的标准。即决定子系统将如何被组合成层
次的体系结构。
null • 确定层的数量。太多使系统复杂,太少降低子系统的功能独立性。
• 命名层并将子系统分配到某个层。确信同层的子系统间的通信以及和其他层的子系统间的通信遵循软件体系结构设计思想。
• 定义每个层的接口。
• 精化子系统以建立每个层的类结构。
• 定义层间通信的消息模型。
• 评审层设计以保证层间的耦合度最小。
• 迭代以精化分层设计。null 2、并发性与基于体系结构风格的子系统分配
当系统有许多并发行为时,要划分任务,简化并发行为的设计与编码。一个任务指系统中的一个过程,有时就是进程的同义词。并发任务可通过检查每个对象的状态图而定义,如果事件和变换流指明在任意时刻只有单个对象是活跃的,则是一个控制线程。即使一个对象向另一个对象发送消息,只要第一个对象等待响应,控制线程就继续。如果第一个对象不等待,则控制线程分叉。
OO系统中的任务是通过孤立控制线程而设计的。例如当SafeHome系统正在监控其传感器时,它也可以拨号到监控站以检验连接。涉及这两个行为的对象(传感器、监控站)是同时活跃的,每个对象参与一个独立的控制线程并被定义为独立的任务。如果监控和拨号活动顺序地发生,则只设计单个任务。 null 对象-行为模型对分析类间或子系统间的并发性提供了支持。如果类和子系统不是同时活动的,则不需要并发处理,它们可以实现在同一个处理器硬件上;如果类和子系统必须异步地或同时作用于事件,则被视为并发的。这时有两种选择:分配每个子系统到各自独立的处理器;分配子系统到同一处理器并通过操作系统特性提供并发支持。
分布式系统中, 软件体系结构风格对系统分布
方案
气瓶 现场处置方案 .pdf气瓶 现场处置方案 .doc见习基地管理方案.doc关于群访事件的化解方案建筑工地扬尘治理专项方案下载
具有决定性的影响。选择体系结构风格应考虑以下因素:null
• 根据被开发系统的特点:如系统类型、用户需求、系统规模、使用方式等;
• 网络协议:不同的网络协议支持不同的体系结构风格;
• 可用的软件产品:包括网络软件、OS、DBMS、现有的数据服务器等;
• 成本及其他:购置硬件及软件成本、新开发软件成本、系统的安装与维护成本。此外,如开发人员对所选择体系结构风格下实现技术的熟练程度及开发期限等。
根据以上因素选择合适的体系结构,然后将子系统分配到体系结构的节点上。
null 3、任务管理设计
当一个节点上有多个控制流存在时,需要设计一个对这些控制流进行协调和管理的控制流(即进程或任务)。如设计一个进程,由它负责系统的启动和初始化、其他进程的创建与撤销、资源的分配、优先级的授予等工作。
用以下几步完成任务管理的设计:
• 确定要执行的任务并识别它的特征。
• 确定任务的优先级。
• 创建协调任务来协调所有其他任务。
• 为每个任务设计对象,并定义它们之间的关系。
任务应该用模版详细描述,包括任务名、描述、优先级、服务、由谁管理、如何通信以及在层次中的位置,便于编程人员实现。 null 4、全局资源管理
全局资源包括物理资源(磁盘驱动器、处理器、通信线路)或逻辑资源(数据库、对象)。不但有访问权限的问题,还有访问冲突的问题。所以,应该标识全局资源,并制定访问它们的策略。一般的情况下,如果资源是物理对象,则通过建立协议实现并发系统的访问;如果资源是逻辑对象, Rumbaugh建议对每个资源可创建一个“保护者”对象,控制对该资源的访问(鉴别身份、协调冲突)。
null 5、选择全局控制流机制
控制流是一个在处理机上顺序执行的动作序列。在分析过程中,一般不考虑控制流问题,因为假定所有的对象都能同时运行并在任何需要的时候就能执行它们的操作。系统设计的时候,就要考虑不是每个对象都能奢侈到在自己的处理器上运行。有3种可能的控制流机制:
• 过程驱动控制: 控制来自程序代码中,如程序等待输入。这种控制流大多用于遗留系统并且使用过程化语言编写。当使用面向对象语言,操作的先后顺序分散在许多对象中,通过观察代码来决定输入的顺序将很困难。
• 事件驱动控制: 主循环等待外部事件,一旦事件到达就把与事件相关的信息分配给适当的对象。缺陷是错误过程会阻塞整个应用。
null • 线程: 系统可以创建任意数量个线程,每个线程对应于不同的事件。如果某个线程需要更多的数据,就等待来自操作者的输入。这种控制流机制最直接,但需要比较成熟的支持线程的开发工具,特别是调试和测试工具。
一旦选定了控制流机制,就可用一组控制对象来实现它。控制对象的职责就是
记录
混凝土 养护记录下载土方回填监理旁站记录免费下载集备记录下载集备记录下载集备记录下载
外部事件,存储它们的临时状态,并给出与外部事件相关的边界对象和实体对象的正确的操作次序。
6、数据管理设计
如何存储那些连续的、需要经常重新计算的对象?选择什么样的存储管理模式?
null 3种存储管理机制:
• 普通文件
由操作系统提供的存储机制,数据按字节流存储,适合于存储大容量数据(如图片)。
• 关系数据库
数据抽象比文件高。数据以表的形式存储,表的每一列标识一个属性,每行把一个数据项标识成一个属性值的元组。不同表中的多个元组用来表示单个对象的属性。关系型数据库技术成熟,适合于大的数据集以及对属性数据的复杂查询。
• OO数据库
将对象和关系作为数据储存。提供了继承和抽象数据类型,减少了对象和存储实体之间的转化。查询比关系数据库慢。
下图显示了使用关系数据库对类的存储。
nullnullnull 7、确定边界条件
设计中的大部分工作都与系统稳定的状态行为有关。但必须考虑边界条件:系统如何启动、初始化、关闭以及故障处理。
初始化包括:常量、参数、全局变量、任务及保护独享的处置设置。系统关闭时,应该释放所拥有的全部资源。并发系统中必须通知其他任务,系统要关闭。
运行中出现故障的原因可能是:
• 用户错误,系统应帮助用户纠正错误。
• 硬件错误,网络连接故障等情况需要保存临时状态。
• 软件故障,在程序中多设计出现故障后的出口。
系统设计是不断迭代和演化的过程,要保证设计模型是正确的、完整的、一致的、现实的、易读的。null 8、评审
如果分析模型与设计模型映射(如:每个子系统都能追溯到一个用例或一个非功能需求),则设计模型是正确的;
如果每个需求和每个系统设计问题都提到了,则模型是完整的;
如果一个模型不包括任何冲突,则它是一致的;
如果模型能够实现,则它是现实的;
由非系统设计人员能够看懂模型,则模型是易读的。9.3 对象设计9.3 对象设计 系统设计相当于大楼的建筑平面图,规定了每个房间的用途,以及房间与房间之间、房间与外部环境之间的连接机制。对象设计着重于每个房间的内部细节。
对象设计的主要任务是:
• 定义对象完整的接口
• 设计对象内部结构
• 构件选择
• 重组及优化
系统分析确定了问题域对象,以及它们之间的关系、相关的属性、操作。系统设计确定了子系统和大多数重要的求解域对象。对象设计要精细这些对象(这里的对象包括子系统),并可能定义其他的求解域对象。null 1、定义对象的接口
对象的接口也称为对象的协议、对象的界面。它通过定义对象可以接收的每个消息和当对象接收到该消息后完成的相关服务来描述。接口提供了一种方法,把对象基于操作的功能说明与具体实现区分开来,使得任何依赖和使用接口的客户不必依赖于接口的具体实现,有利于接口实现的替换。
接口描述可以用UML中类图一样的符号,省略属性部分,《interface》要包含在类名部分中。比较多的人喜欢用程序设计语言来定义接口,以便用编译器来发现接口描述中的错误和不一致。
下图给出了“转账” 的Java接口描述。null//provided interfaces:
Public interface Transfers{
public Account create (Customer owner, Money balance,
AccountNumber account_id);
public void Deposit (Money amount ,String reason);
public void Withdraw (Money amount, String reason);
}
要确定某个对象完整的接口,必须考察与它有关的所有用例,将与它有关的所有消息抽取出来,形成该对象完整的界面。
对于包或构件,当有依赖关系指向它的时候,就有可能表示该包或构件需要提供一个接口。null2、设计对象内部结构
• 确定遗漏的属性和操作:
系统分析和设计时集中考虑应用域,忽略与实现相关的细节,这时就应该增加上。
• 指定类型,声明可见性:
属性:确定类型、数据结构。除了分析活动中确定的属性,还包括一些其他属性,这些属性用来表示和其他类的对象关联的对象引用(关联的实现)。
操作:确定参数、返回值及类型。
为了确定每个属性和操作的访问权限,UML定义了3种可见性符号,即在属性和操作的说明前加上前缀:null -:私有的, 只能由定义它的类访问,子类和其他类
都不能访问。
+:公有的, 任何类都可以访问。公有的操作确定了
对象的接口。
#:保护的, 可以由定义它的类以及该类的子类访问。
• 设计关联:
OOPL一般不提供“关联”的直接实现,一般用指针或对象引用来实现关联。(有UML建模工具自动完成关联到引用的转换)。
单向一对一关联:ZoomInMapAreaZoomIn1 1MapArea-Target: MapArea
:null 对于双向一对一关联的实现,则在MapArea中设置一个引用ZoomIn的属性。并增加相应的操作,修改属性并避免无穷循环。
一对多关联: LayerElement
1 *LayerElement
-LayerEle: Set-Containe: Layer Layer的Set取决关系的约束条件。如层中的元素要排序,则用Array或Vector代替Set。双向一对多关联的实现null 多对多关联:RecordElement
* *RecordElement
-RecordEle: Set-Containe: Set双向多对多关联的实现 对于多对多关联,可以将 “关联” 作为一个独立的类,形成两个二元关系,可降低重数,方便实现。null • 设计操作的算法
分析类的状态图,从每个状态转移前后的动作说明获取每个方法体的逻辑结构。而顺序图中的消息一般对应状态图中引起状态转移的事件或动作。 类名可见性:属性列表可见性:操作1(参数表)
可见性:操作2(参数表)
…… 方法1
方法1过程体 方法2
方法2过程体 方法n
方法n过程体…消息消息消息null3、构件选择
选择系统运行的软、硬件平台,包括商品构件(更可靠、有效、健壮)、DBMS、中间件、企业应用程序框架(特定的应用)等,目的是尽可能多地减少需要开发的自定义对象的数量。由于商品构件支持大多数系统,较为复杂,需要学习的投入,可能还要作适应性修改。
4、重组与优化
(1)提高可复用性
对象设计给出了开发阶段中再次检查应用程序和求解对象间继承层次的机会。
设计完善的继承层次的主要优点是:
• 可以复用更多的代码,产生较少的冗余。
• 代码是可扩展的,可用来创建更特别的类。
null 但是通过继承复用是有代价的,开发人员需要正确的预见所创建的类的哪些行为需要共享、哪些行为需要由以后的新类细化,通常还不会知道以后所有可能的新类。另外,一旦开发人员为共享代码定义了继承层次,抽象类的接口难以改变,因为许多子类和客户类都依赖它们。
设计通过继承层次复用的方法是:
• 检查大量相似的类,抽取出它们的共同行为。
• 给出一层抽象概念,并从预期的变化中抽取出一个具体类。如AbstractFactory等设计模式(见下一节“设计模式”)都使用了继承来防止预期的变化。
null (2)优化访问路径
效率低的系统性能的常见原因是访问必须的信息时对多个关系的重复遍历。为了识别较低的访问路径,Rumbaugh建议对象设计者应该考虑下列问题:
• 对于每个操作:需要多少次遍历?遍历哪些关系?常用的操作不应该有许多遍历,应该直接通信。如果缺少直接通信,应该在两个对象间增加另外的关系。有一个Demeter法则,称“只同你的直接朋友对话”,指在软件设计中,一个方法只与由关联连接的相邻对象通信。好处:易理解、易修改、效率高。
• 对于每个关系:有“多重”关系?重数是必需的吗?检索过程中,关系中的“多”端是否经常出现?如果有,应该试着将“多”减少为“1”。否则,应为“多”端排序或建立索引以改进访问时间。null 效率低的另一个原因是过多的建模。分析时确定了许多类结构,但设计时发现没有任何意义的信息。因此对象设计者应该问:
• 对于每个属性:哪些操作用到了这个属性?只有
set()、get()操作吗?如果是,能否移到调用它的对象中去?如果某些类有很少的属性和行为,并且与其它类相关,可将这些类退化成属性(减少了类的数目)。这样做的目的是使模型变得简单、直接。9.4 设计模式9.4 设计模式 1、概述
模式 (Pattern) 是解决特定领域问题的经验,可以帮助人们在软件开发过程中对于经常重复出现的问题制定成功解决的方案。
模式的概念最初来自于建筑学领域,用模式描述建筑物的建筑元素(Alexander,1979),它合并了被认为是好的设计的实践经验。90年代中期,软件设计人员认识到了这些重复出现的软件设计问题。94年Gamma等4人(简称“Gang of Four”)合著的《设计模式:可复用面向对象软件的基础》提出了用设计模式进行解决,并对设计模式进行了分类描述和解释。96年由Buschmann等5人合著的《面向模式的软件体系结构》将模式跨越不同的抽象层次,提出了高层的体系结构模式、中层的设计模式和低层的习惯用法。本章主要针对设计模式进行讨论。null Gamma提出:设计模式解决特定的设计问题,并使得面向对象设计更灵活、优美和可复用。它们通过将新的设计基于以前的经验之上而帮助设计者复用成功的设计。熟悉这样的模式的设计者可以立即应用它们到设计问题中,而不需要重新去发现它们。
因此,在OOD过程中,开发人员应积极去选择并应用现存的可复用的设计模式,而不是试图创建新的设计模式。
每个模式都有伴随定义的语境和强度。语境解释了模式适用的情况。强度是语境中的元素,有某种程度上的不同。如果问题的环境与模式的语境和强度相匹配,该模式就适合于你的应用。如果模式限制必须有灵活的环境,使用模式设计就要付出代价。
null 由于设计模式的复杂性和抽象性,软件设计人员一般从以下几方面考虑选择适合的设计模式:
• 考虑设计模式解决设计问题的步骤,从中借鉴良好的设计经验。
• 考虑设计模式所要解决的问题,将之与自己的问题匹配,从而做出选择。
• 从更高一层着眼,分析所有的设计模式之间的关系,研究目的相似的模式(要求设计人员对设计模式非常的熟悉)。
• 考虑设计中哪些是可变性和可扩充性。
设计模式在软件设计中的应用主要取决于设计人员的主观意识和熟悉模式的程度。null2、设计模式的分类
根据“Gang of Four”的分类准则,按模式的使用目的(即“用来完成什么工作”)来划分,可分为以下几种类型:
创建型:创建对象
结构型:处理类和对象的组合
行为型:对类或对象如何交互、如何分配职责进行描述
(1)创建型模式
• Abstract Factory(抽象工厂):提供了创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
• Builder(生成器):将一个复杂对象的构建与它的表示分开,使得同样的构建过程可以得出不同的表示。
• Factory Method(工厂方法):定义了一个创建对象的接口,让子类决定将哪个类实例化。该方法使一个类的实例化延迟到其子类。null • Prototype(原型):用原型实例指定创建对象的种类,并通过复制原型来创建新的对象。
• Singleton(单件):一个类仅有一个实例,提供对它全局访问。
(2)结构型模式
• Adapter(适配器):将一个类的接口转换成客户希望的另一个接口。该模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
• Bridge(桥接):将抽象部分与它的实现部分分离,使它们都可以独立的变化。
• Composite(组合):将对象组织成“整体-部分”的层次结构。该模式使得客户机对单个对象和复合对象的使用具有一致性(进行同样的交互)。
• Decorator(装饰):动态的给一个对象添加一些额外的功能。就扩展功能而言,该模式比生成子类方式更为灵活。null • Facade(外观) :为子系统中的一组接口提供了一个统一的界面。该模式有助于为复杂子系统提供一个简单接口,使得子系统容易使用。
• Flyweight(享元):运用共享技术有效的支持大量细粒度的对象。
• Proxy(代理):使一个对象(如组件的客户机)与一个对象代表而不是对象本身通信。
(3)行为型模式
• Chain of Responsibility(职责链):为避免请求的发送者与其接受者耦合在一起,给予多个对象都有处理这个请求的机会。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它。
• Command(命令):将请求分装为对象(将请求与其执行分开),允许系统以不同请求、队列或日志请求作为参数来表示客户,并支持无法执行的操作。null • Interpreter(解释器):给定一种语言(如脚本语言),定义语法的表示方法和解释器,解释器使用该方法来解释语言。
• Iterator(迭代器):提供了连续访问一个聚集对象中各个元素的方法,而不需要暴露该对象的内部表示。
• Mediator(中介者):定义一个中介对象,来封装一组对象交互的方式。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且还允许对象的交互独立变化。
• Memento(备忘录):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,使其以后能够恢复。
• Observer(观察者):在对象间定义的一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。null • State(状态):允许一个对象在其内部状态改变时改变它的行为。对象会改变类。
• Strategy(策略):定义一系列的算法,对每个算法进行封装,并使它们能够交互。该模式使得算法的变化可独立于使用它的客户。
• Template Method(模版方法):定义操作中算法的框架,将某些步骤推迟到子类中进行。该模式允许子类在不改变算法结构的情况下,改进算法的某些步骤。
• Visitor(访问者):表示作用于某个对象结构中的各元素的操作,使得在不改变各元素的类的前提下定义作用于这些元素的新的操作。
以上是“四人帮”模式,还有其他模式。“五人帮”对模式的扩展及增加的分类准则同学们可看相关
书
关于书的成语关于读书的排比句社区图书漂流公约怎么写关于读书的小报汉书pdf
籍。null 例1:使用设计模式消除实现的依赖性
如编写一个能够在多种风格的窗口上运行的程序。程序本身不用知道或依赖于窗口、滚动条、按钮、菜单等对象特定的、不同的外观感觉。 Abstract Factory模式为每个可替代的对象(如抽象窗口、抽象按钮)提供一个抽象类及其接口,由每个具体类(称为factory)实现它的抽象类的接口操作。(见下图)
注意到,MotifyFactory和MacFactory有着同样的接口createButton(),但产生的按钮不一样,客户只需访问抽象类中的接口。该模式支持将接口与具体实现分开,这使得将来如果增加新的factory,不会改变应用程序。nullAbstractFactorycreateWindow() createButton()MotifFactorycreateWindow() createButton()MacFactorycreateWindow() createButton()抽象窗口抽象按钮Motif窗口Mac窗口Motif按钮Mac按钮客户AbstractFactory设计模式(虚线箭头表示调用关系)提供接口实现接口(创建按钮)只需访问接口和抽象类null命令execute()具体命令2execute()具体命令1execute()接收者action1() action2()用户选择捆绑例2:使用Command模式对控制流进行封装。
在交互式系统中,希望在不知道请求内容的情况下,能实现执行、取消执行或存储用户请求。把请求与处理分开的关键在于把请求变成命令对象,它继承了抽象命令类。命令类定义了如何执行、取消执行或存储指令,而具体的类实现特定的请求。Command模式允许封装控制,以便与特定请求相独立,平等对待用户请求。Command模式null命令execute()粘贴命令execute()拷贝命令execute()文件paste() copy()菜单项捆绑* 菜单* 如:可用Command模式把菜单选项与活动分离开来(如下图),把控制流集中到命令对象中,不同的命令对象实现不同的执行请求(拷贝命令、执行命令),而不是分布到边界对象(菜单项)和实体对象(文件)中去。Command模式的例子null 例3:使用Proxy模式的设计
Proxy模式有许多用途:提高效率、易于存取、防止越权访问等。一个客户机需要访问另一个组件的服务,但对组件进行直接和无限制的访问可能是低效的甚至是不安全的,需要额外的控制机制。 Proxy模式使客户机与组件代表而不是组件本身通信。这种代表(称为代理)提供组件接口并执行附加的前期处理和后期处理。
Proxy模式的模版为: 抽象原件服务1()服务2() 原件服务1()服务2() 代理服务1()服务2()客户机
任务null 其中:
客户机的责任:
• 利用代理提供的接口来请求特殊服务。
• 完成它自己的任务。
抽象原件的责任:
• 对代理和原件,服务作为一个抽象基类。
原件的责任:
• 实现一个特殊服务。
代理的责任:
• 对客户机提供原件接口。
• 确保安全、有效和正确的访问原件。
下面给出了2个具体例子说明使用Proxy模式提高运行效率的设计和防止越权访问的设计。null(1)考虑将表示图片的对象存入文件。从文件中装入所有组成图片像素的代价是昂贵的,显示图片之前没有必要装入所有图片数据。用Proxy模式可以实现这种优化。 Image
filename:String data: byte[ ]width( ) height( ) paint( ) Image
filename:Stringwidth( ) height( ) paint( ) RealImage
data: byte[ ]width( ) height( ) paint( ) ImageProxy
filename:Stringwidth( ) height( ) paint( )转换前的设计 转换后的设计 图像 1 0..1null ImageProxy提供了和Image一样的接口,某些操作(如width()和height())由ImageProxy处理,但是当需要画出Image的时候,ImageProxy才从磁盘中读入数据并生成一个RealImage对象。如果客户不调用paint()操作,就不用创建RealImage对象,节省了实际的计算时间。调用的类只通过Image接口访问ImageProxy和RealImage。
(2)银行信息系统的一个例子规定:经纪人不能访问由其他经纪人管理的一些档案。因此必须对系统的访问权限动态建模。下图给出了用Proxy模式实现的访问。
对每一个档案,创建了档案代理以保护档案并检查访问权限。合法经纪人与档案代理之间的访问关系指出了经纪人可以访问哪个文件。为了访问档案,经纪人先给档案代理发送消息,档案代理先检查发出调用的经纪人是否与档案代理有访问关系。如果授权访问,档案代理将认证操作发给实际的档案对象。
null 图中访问关系类包含有一组经纪人可以访问档案的操作。档案代理中的每个操作首先调用isAccessible()操作,检查发出调用的经纪人是否具有合法的访问权。一个访问关系可以用于多个授权的访问控制。档案代理buy( )
sell( )
estimateYield() 档案buy( )
sell( )
estimateYield()1 1 访问
isAccessible()1经纪人*null3.模式的基本元素和描述模版
一般而言,一个模式有四个基本要素:
(1)模式名称(pattern name): 对某一模式的简练概括所提取的名字。
(2)问题(problem): 描述了设计模式所解决的问题,或者说使用设计模式可以在设计中避免的一些缺点。
(3)解决方案(solution): 给出了问题的解决方案,描述了该方案设计中的组成成分以及它们之间的相互关系、职责和协作方式。
(4)效果(consequences):对应用某种设计模式的一种权衡,侧重于对时间和空间的衡量,分析了应用设计模式之后的优点和缺点。
null 设计模式有以下几种描述方法:
(1)自然语言描述法
采用自然语言来描述设计模式及其所解决的问题。自然语言比较容易理解,对于设计模式的理解比较方便。但是,自然语言过于随便,没有客观性,难于提供一个从现实中所要解决问题到设计模式之间的良好过程。(2)UML描述法
UML描述方法是 Gamma等人在介绍了设计模式时采用的方法,该描述法清晰和统一,符合大部分软件设计人员的习惯。采用UML中的类图不仅可以描述设计模式中的组成部分,而且可以方便的描述模式中类及对象之间的关联、聚合、继承和各种依赖关系。
null(3)形式化方法
形式化方法主要利用形式化规格说明语言对软件设计模式进行严格地描述,并采用数学推理的方法应用设计模式来改进软件设计质量。主要用于科学研究及一些要求比较高的软件设计。
对于软件设计而言,模式的语义部分大部分采用自然语言来描述,而解决方案采用UML描述。
描述模版:
• 模式名与分类
• 意图(做什么、基本原理)
• 适用性
• 模式结构
• 参与者
• 效果null4、设计模式引入软件设计中的一般步骤
对现有的软件设计模式的应用一般有两个方面:
• 在软件系统设计开始阶段,就应用设计模式对软件体系结构(往往是子系统结构)进行设计。也就是从软件设计一开始就从应用设计模式。
• 在系统初步设计完成后,针对系统内某些组件或模块的性能要求,在设计方案中加入某个设计模式使系统的某些模块更加优化和灵活,也就是在系统整体设计后用设计模式对系统的部分结构进行优化。
由于设计模式的复杂性,使得模式在提出很长的一段时间后,设计人员在将其应用到具体的软件系统设计中时,仍然存在很多困难。主要原因有两点: null
• 对软件设计模式的总体把握以及具体模式的理解都还不够透彻。
• 没有一个有效的方法和步骤来指导软件设计人员如何应用这些设计模式。
软件设计模式应用于软件设计中的一般步骤:
(1)划分求解域的类型
软件设计模式的三个类型(创建型、结构型和行为型),用于分别解决不同类型的问题。因此要对所要解决的问题进行抽象,判断问题属于创建型,还是结构型,或者行为型。所要解决的问题可能有多种类型组成,也可能不涉及到现有的软件设计模式。
null (2)判断是否可以借鉴某种类型的设计模式来设计或优化。如果符合某种类型范畴,则从该类型的模式中选择合适的模式。
该阶段要求设计人员:
·理解所选择的模式,注意模式的适用条件和模式的使用效果,确定是否适合要解决的实际问题。
·研究模式的结构、组成、类及对象的协作等关系。
(3)规划问题和匹配模式。
将要求解的问题与选择的设计模式所能解决的问题进行比较,找出共性。在求解的问题域内考虑那些元素对应现有模式中的类,以及模式中各角色的如何确定等等。如果发现选择的设计模式并不合适,返回到上一步重新进行设计。
null (4)对选取的模式进行变体,以适应问题的需要。
在应用某个设计模式时,往往会发现并不完全适合所要解决的问题。同时,由于现有的模式的一些局限性需要对其进行扩充。因此要对该模式的原始结构进行修改,使之适应系统的需要。
(5)对使用模式后的软件体系结构进行精化。null 5、例:
设计模式在行业安全管理平台设计中的应用研究
本系统目标是为电力行业提供一个绘制电力接线图的平台,使之产生其它应用系统的输入。该平台有两个要求:首先,输出必须是矢量图。这样,图形不会产生放大缩小失真问题。其次,图形必须具有智能连接关系的判断。换句话说,图形必须能够判断所处的图形位置,并根据位置信息和电气元件状态来判断是否带电,从而呈现不同的颜色。正因为如此,要求产生的接线图包括联结关系属性,并且易于使用。
(1) 系统分析
对问题进行分析,分析该平台中对象的粒度关系。如下图所示:null 对于电力系统接线图而言,由于包含电路逻辑连接信息,所以,整个连接图由逻辑单元组成。逻辑单元由逻辑上的电气元件组成。电气元件在系统中的表示由点、线、圆等基本几何元素构造而成。
除了粒度之外,该系统要为用户提供的一个矢量图形编辑环境,能够快速绘制电力系统接线图,必须轻便灵活、简单方便,具有强大的电力图元集。电力图元是电力接线图中逻辑上最小的单元,例如,开关,变压器等等。
然而,由于各地需求的差异,还必须保证该系统具有良好的扩充性和适应性,不用因为图元或元件的标识差异而重新开发或维护。null 为此,将系统分为两个大模块:
• 基于元件的连接图形生成模块
• 为用户提供一个可以通过对基本元素组合定制元件的图形符号及属性(图元)的模块。
只有这样,系统才可以适应各地电力单位不同的需要而不必重新开发程序。这里充分体现了系统对扩充性要求。
因此,系统在采用面向对象设计技术设计时,拟采用已经发布的优秀设计模式,实现复用性和灵活性。由于要创建图形对象,首先想到的就是选择创建型设计模式。然而,创建型模式能否很好的满足我们的要求以及如何选择合适的创建型模式,需采用下面所描述的过程来进行分析。null (2) 应用设计模式进行初步设计
① 分析问题,划分问题类型。
如上所述,该系统主要产生矢量电力接线图。通过对该领域的分析和抽象,可以判断出问题应该属于创建类型。
但是,创建型设计模式中包含了抽象工厂(Abstract Factory)、生成器(Builder)、工厂方法(Factory Method)、原型(Prototype)、单件(Singleton)等几种对象创建型模式,为了选择适合的设计模式,进而做下一步分析。
② 选择适合的创建模式
在所有创建型设计模式中,Singleton模式主要应用于系统中要求某个类在该系统中只有一个实例的情况。因此,可以排除Singleton模式。
null Builder模式将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示,并不满足系统对图元可扩充性的要求。
Factory Method模式,主要产生一个用于创建对象的接口,让子类决定实例化哪一个类,使得一个类的实例化延迟到其子类。对于所要设计的平台而言,增加任何一个新的图元,必须增加相应的工厂类的实例,随着系统内子类数目的激增,会导致系统性能下降,后期程序的维护过于复杂。显然,也不符合系统对图元扩充性的要求。
Abstract Factory并没有很大的改进,因为它需要一个同样庞大的设备类别层次。
null Prototype模式对电力逻辑平台框架可能是最好的,它仅需要为每个图元类实现一个Clone(复制)操作,这样可以减少类的数目。由于电力接线图是多个图元的多个实例组成,显然Prototype可以较好的满足这一点。
该模式的结构示意图见下图1。
③ 规划和匹配所选择的设计模式
匹配Prototype模式得到的设计结构参见下图2。
null其中Prototype:定义一个复制自身的接口
ConcretePrototype;实现一个复制自身的操