OOAD学习目标:
1.A critical,fundamental ability in OOAD is to skillfully assign responsibilities to software components.(面向对象分析设计种至关重要的的能力是熟练地为软件部件分配职能)
2)GRASP patterns ,nine fundamental priciples in object design and responsibilities assignment.
什么是分析和设计:
1)分析强调对问题的调查研究而非解决方案
2)设计强调满足需求的概念上解决方案而不是其实现
3)有益的分析和设计可以概括为做正确的事和正确地做事
什么是面向对象
面向对象将功能通过对象来实现,将功能封进对象中,让对象实现具体细节。
什么是OOAD
1)OOAD 的方法要求设计中要映射现实世界中指定问题域中的对象和实体
2)OOAD的精髓是透过对象(事情、概念、实体)考虑问题域和概念上的解决方案
3)OOA强调在问题域内发现和描述对象
4)OOD强调定义软件对象以及他们如何协作以实现需求
OOA做的事是
1)对问题域进行理解并抽象成概念(对象)
2)找到概念之间的联系
3)找到概念中的属性
问题域:被开发系统的应用领域,即现实世界中由这个系统进行处理的业务范围
用例:人们如何使用应用的场景或情节的记录
面向对象分析的结果可以表示为领域模型,在领域模型中展示重要的领域概念或对象,领域模型表述了重要的概念及其关联和属性。领域模型斌不是对软件对象的描述,它使真实世界领域中的概念和想象可视化,又叫概念对象模型。
交互图:面对对象设计关注定义软件对象以及对象间的协作,交互图为描述协作的常见方法,交互图有通信图和顺序图。
设计类图:有效表示类定义的静态图视图。
UML 统一建模语言,是描述、构造和文档化系统制品的可视化语言,其目标为使用面向对象的思想建立模型系统
UML三种应用方式:
1)UML作为草图
非完整,不正式的图
2)UML作为蓝图
相对详细的设计图,用于:
1.逆向工程,以UML图方式对现有代码进行可视化,使其易于理解。
2.代码生成,前向工程
3)UML作为编程语言
1.用UML完成软件系统可执行规格说明
2.可执行代码能够被自动生成
3.UML作为编程语言仍处于开发阶段
UML图定义
用例图:描述角色以及角色与用例之间的连接关系
类图:描述系统中的类,以及对象、接口、协作等事物之间的关系
交互图:描述对象间如何协作,包括序列图(顺序图)和协作图
状态图:描述类的对象所有可能的状态,以及事件发生时状态的转移条件
活动图:描述用例要求所要进行的活动,以及活动间的约束关系
包图:描述系统的逻辑架构
部署图:描述系统的硬件配置、部署以及软件构件和模块在不同节点上的分布。
UML五类图(9种图形)定义
1)第一类:用例图
从用户角度描述系统功能,并指出各功能的操作者
2)第二类:静态图
包括类图、对象图和包图
3)第三类:行为图
描述系统的动态模型和组成对象间的交互关系
行为图包括状态图、活动图
4)第四类:交互图
描述对象间的交互关系
5)第五类:实现图
包括构件图和部署图
构件图描述代码部件的物理结构和部件之间的依赖关系
UML图分类
UML中的几种关系
1.泛化(Generalization):带三角箭头的实线,箭头指向父类
2.实现(Realization):带三角箭头的虚线,箭头指向接口
3.关联(Association):带普通箭头的实心线,指向被拥有者
4.聚合(Aggregation):带空心菱形的实心线,灵性指向整体
5.组合(Composition):带实心菱形的实线,菱形指向整体
6.依赖(Dependency):带箭头的虚线,指向被使用者
UML图关系
迭代、进化和敏捷
敏捷模型(Agile modeling)是有效应用 UML的关键
敏捷开发核心原则:简单、顺应变化、可递增
敏捷开发:通常应用时间定量的迭代和进化式开发、使用自适应计划、提倡增量交付并包含其他提倡敏捷性的方法和实践。
具备进化式精化计划
短时间定量迭代需求和设计
倡导简易、轻量等敏捷性的实践和原则
敏捷建模:
敏捷方法不意味着不进行任何建模
建模的目的主要用于理解和沟通,并不是构建文档
不要对所有或大多数软件设计建模使用UML,可以将简单设计推延到编程阶段
尽可能使用最简单的工具
不要单独建模,建模目的式发现、理解和共享大家的理解
敏捷建模的特点:
轻量型的开发过程
重视敏捷建模的实践
迭代式的开发过程
以人为主导的开发环境
对知识转移的支持
统一过程 Unified Process UP
UP核心思想:短时间定量迭代、进化和适应性开发
UP项目将工作和迭代组织为四个主要阶段:初细构移
1)初始:大体上的构想,业务案例,范围和模糊评估
2)细化:已精细化的构想,核心架构的迭代实现,高风险的解决方案,确定大多数需求和范围以及进行更为实际的评估
3)构造:对遗留下来的风险较低和比较简单的元素进行迭代实现,准备部署
4)移交:进行BETA测试和部署
科目:在一个主题域的一组活动。
需求分析
需求就是系统必须提供的能力和必须遵从的条件
需求分析最大的挑战是寻找、沟通和记录什么是真正需要的,并能够清楚地讲解给客户和开发团队的成员
需求变更不可避免,所以有效管理是必不可少的。
作用:
客户与开发人员之间的桥梁
明确系统做什么的问题
降低开发风险
需求分析过程:
需求获取
需求建模
需求文档
OOA 分析方法:以对象为基本的处理单元,将对象的数据和操作进行封装,特点是加强了解,改进与分析有关的各类人员间的交流,适应性强,能实现软件复用,建模技术UML
结构化分析方法:“分解”和“抽象”为钟点,以数据流为核心主要研究数据流动及处理。特点是将复杂问题分解简单化,抽象问题的本质而暂时忽略细节,通过数据流程图描述当前系统的逻辑模型,建模技术就数据流图业务流图数据字典。
需求复用:
需求复用的思想来源于软件复用
需求不是独一无二的
复用的核心是软件构件技术
统一过程种,需求按"FURPS+"模型分类
Functional:特性,功能,安全性
Usability:人性化因素,帮助,文档
Reliability:故障频率、可恢复性、可预测性
Performance:响应时间、吞吐量、准确性、有效性、资源利用率
Supportablity:适应性、可维护性、国际化、可配置性
+为 实现,接口,操作,包装,授权等辅助性和次要因素
用例
目标:确定和编写用例,在一个基本样式种使用摘要,非正式和详述等用例形式
用例:一组相关的成功和失败的场景集合,用来描述参与者如何使用系统来实现其目标
场景:参与者和系统之间一系列特定的活动和交互,也称为用例实例
参与者:是某些具有行为的事物,可以是人、计算机系统或组织
为什么使用用例
让外行人看懂内行人要做什么
强调用户的目标和观点
用例即需求,主要目的是说明系统的功能性或行为性需求
用例的优越性在于,能够根据需要对复杂程度和形式化程度进行增减调节。
用例三种常用形式
摘要 brief:简洁的一段式概要,用于主要成功场景
非正式 casual:非正式的段落格式,用几个段落覆盖不同场景
详述 full-dressed:详细编写所有步骤及各种变化,同时具有补充部分,如前置条件和成功保证
用例定义
为每个用户目标分别定义用例
用例名称应同用户目标类似
用例名称应该使用动词开头
目标级别的用例与用户目标一一对应
分散的CRUD目标合并成一个CRUD用例
EBP(Elementary Business Process)测试
EBP定义:
一个人于某个时刻在一个地点执行的任务,用以响应业务事件
该任务能够增加可量化的业务价值,并且以持久状态留下数据
进行需求分析时,将用例聚焦于基本业务过程级别
用例图组成
参与者:系统交互角色
用例:变量在内一组动作序列描述,系统执行这些动作并产生传递特定参与者价值的可观察结果
系统边界:用来表示正在建模的边界
箭头:用来表示参与者和系统通过相互发送信号或者消息进行交互的关联关系
领域模型:对领域内的概念类或现实世界中对象的可视化表示,领域模型也称为概念模型,领域对象模型、分析对象模型
目标:
确定当前迭代相关的概念类
创建初始的领域模型
为建模提供适当的属性和关联
使用UML表示法,领域模型被描述为一组没有定义操作的类图,可展示:
领域对象或概念类
概念类关联
概念类属性
领域模型是OOA中最重要和经典的模型
确定一组对象或概念类 是 OOA的核心
什么是概念类
概念类是思想、事物或对象,更正式地将,概念类可以从其符号、内涵和外延来考虑。
OO关键思想:
领域层软件类的名称要源于领域模型中的名称,以使对象具有源于领域的信息和职责,可以减少人们思维与软件模型之间的表示差异。
如何创建领域模型:
以当前迭代中所要设计的需求为界:
1.寻找概念类
2.将其绘制为UML类图中的类
3.添加关联和属性
如何找到概念类:
重用和修改现有模型
使用分类列表
确定名词短语
如何绘制领域模型
根据现有需求使用分类列表和确定名词的方式列出备选概念类
绘制领域模型
找到并加入必要联系
确定并加入概念类属性
描述类:包含描述其它事物的信息
何时需要描述类?
需要独立于现有实例的描述
删除所描述的事物的实例时,这些需要被维护的信息不会被关联删除
减少冗余重复信息
关联:
在领域模型中考虑如下关联:
若存在需要保持一定时间的关系,语义表示为关联
从常见关联列表中派生的关联
关联命名:类名-动词短语-类名的格式为之进行可读性有序命名
领域模型实例:
系统顺序图(SSD, system sequence diagrams ):为阐述所讨论系统相关的输入输出事件而快速简单地创建的制品
目标:确定系统事件,为用例场景创建系统顺序图
用例文本及其所示的系统事件是创建SSD的输入
每个系统时间都对应一个系统操作
SSD操作可以在操作契约中进行分析,在词汇表中被详细描述,并且作为设计协作对象的起点
应为每个用例的主要成功场景,频繁发生或复杂的替代场景绘制SSD
处理销售场景的SSD
系统事件命名以动词开始
SSD Within the UP
SSD是用例模型的一部分,可视化隐含交互
UP初始阶段不引入SSD,大部分创建于细化阶段
有利于识别系统事件细节以明确系统必须被处理和设计的操作
有利于编写系统的操作契约
有利于对估算的支持
操作契约:使用前置或后置条件的形式描述领域模型里对象的详细变化,并作为系统操作的结果,包括操作,交叉引用,前置条件,后置条件。
契约主要输入为SSD中确定的系统操作,linguistic模型和领域专家的见解
系统操作:作为黑盒构件的系统在其公共接口中提供的操作
后置条件:描述了领域模型内对象状态的变化
领域模型状态变化包括:
创建或删除实例
形成或消除关联
改变属性
契约在何时有效:
用例是项目需求的主要知识库,但对用例而言所需状态变化的细节和复杂性难以处理或过于细节化。
契约创建的指导:
从SSD得出系统操作。
系统操作复杂,结果不明显,或者用例不明确,为其创建操作契约。
07 OOD UML迭代图
逻辑架构:
软件类宏观组织结构,将软件类组织组织为包(或命名空间)、子系统和层。
层:较为粗粒度的对类、包或子系统分组,具有对系统主要方面加以内聚的职责。
OO系统中通常包括:UI层,应用逻辑和领域对象层,技术服务层。 严格的架构只能调用相邻下层,宽松架构可调用任何其下层
架构:
一组重要决策,其中涉及软件系统组织,对结构元素及其组成系统所用接口的选择,这些元素特定于其相互协作的行为,这些结构和行为元素到规模更大的子系统的组成,以及指导该组织结构的结构风格。
交互图:
顺序图:以一种栅栏格式描述交互,其中在右侧添加新创建的对象。
通信图:以图或网格格式描述对象交互,其中对象可以置于图中任何位置。
交互图消息表达式 return:=message(parameter:parametertype):returnType.
GRASP
职责驱动设计 RDD:就对象的角色而言,职责与对象的义务和行为相关,职责分:行为和认知。
对象的行为职责包括:
自身执行一些行为,如创建对象或计算
初始化其他对象中的动作
控制和协调其它对象中的动作
对象的认知职责包括:
对私有封装数据的认知
对相关对象的认知
对其能够导出或者计算的事物的认知。
职责和方法不同,职责是抽象,而方法实现了职责。
模式:模式是成对的问题/解决方案,并且具有广为人知的名称,能用于新的语境中,同时对新情况下的应用、权衡、实现、变化等给出建议。
1.名称:创建者
问题:谁创建了A
解决方案:若B包含组成聚集了A,B记录了A,B紧密地使用A,B具有A的初始化数据,则将创建类A的职责分配给B
2.名称:信息专家
问题:给对象分配职责的基本原则是?
解决方案:把职责分配给具有完成该职责所需信息的那个类。
3.名称:低耦合
问题:如何减少因变化产生的影响
解决方案:分配职责以使耦合保持在较低水平
4.名称:控制器
问题:在UI层之上首先接收和协调系统操作对象是什么
解决方案:把职责分配给能代表下列选择之一的对象:
代表全部系统、根对象、运行软件的设备或主要的子系统
代表发生系统操作的用例场景
5.名称:高内聚
问题:如何使对象保持有内聚、可理解、可管理,同时支持低耦合的附加作用
解决方案:职责分配应保持高内聚,以此评估备选方案
基于GRASP的OOD
用例实现:
描述某个用例基于协作对象如何在设计模型中实现
设计者能够描述用例的一个或多个场景的设计,每个设计都成为用例实现
UML是描述用例实现的常用语言
注意,如何通过GRASP进行类之间关联和职责划分
对象间的可见性:
可见性是一个对象看见其他对象或引用其他对象的能力。
为了使发送者能向接收者发送消息,发送者必须具有接收者的可见性,也就是持有接收者对象的某种引用或指针。
可见性:
对象A到B的可见性通常有四种方式:
属性可见性:B是A的属性
参数可见性:B是A中方法的参数
局部可见性:B是A中方法的局部对象
全局可见性:B具有某种方式的全局可见性
为了使对象A能够向对象B发送消息,对A而言,B必须是可见的。
使用面向对象语言将设计制品映射为代码:
使用OOL需要为类、方法和接口定义写源码。
DCD Designed Class Diagram设计类图,设计模型
DCD描述了类或接口名称、超类、操作的特征标记以及类属性,在OO中创建基本类的定义
DCD如果是UML绘制的,从图形中生成基本类定义。
6.名称:多态
问题:如何处理基于类型的选择,如何创建可拔插的软件构件
解决方案:当选择或行为随类型有所不同时,使用多态操作为变化的行为类型分配职责。
7.名称:纯虚构
问题:当你不想违背高内聚和低耦合或其他目标,但是基于专家模式提供的方案有不合适,哪些对象应承担这一职责。
解决方案:对人为制造的类分配一组高内聚的职责,该类不代表问题领域概念,虚构的事物,用以支持高内聚、低耦合和复用
8.名称:间接性
问题:为了避免两个或多个事物间直接耦合,应如何分配职责,如何使对象解耦合,以支持低耦合并提高复用性潜力
解决方案:将职责分配给中介对象,使其作为其他构建或服务之间的媒介,以避免它们之间的直接耦合。中介实现了其他构件之间的间接性。
9.名称:防止变异
问题:如何设计对象、子系统和系统,使其内部的变化或不稳定不会对其他元素产生不良影响
解决方案:识别预计变化或不稳定之处,分配指责用以在这些变化之外创建稳定接口。
GoF Gang of Four
1.名称:适配器 (间接,纯虚构,多态)
问题:如何解决不相容的接口问题,或者如何为具有不同接口的相似构件提供稳定接口
解决方案:通过中介适配器对象,将构件的原有接口转换为其他接口
适配器模式的宗旨是,保留现有类提供的服务,向客户提供接口,以满足用户的期望。
对于一个已经存在的类,如果它的接口与现有系统的需求不同时,可以考虑设计器模式
接口:一系列方法的 声明,方法特征的集合。接口只有方法特征,而没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为。
面向对象:功能通过对象实现,功能封装进对象中,让对象去实现具体细节。
工厂:这里是简单工厂或者具体工厂,不是GoF设计模式,是GoF抽象工厂模式的简化
工厂返回的是接口而不是类,因此工厂能返回接口的任何实现
分离复杂创建的职责,并将其分配给内聚的帮助者对象,隐藏潜在的复杂创建逻辑,允许引入提高性能的内存管理策略,例如对象缓存或再生。
2.名称:单实例类(单例模式?)
问题:如何只创建唯一实例的类,即单实例类?如何使对象具有全局可见性且单点访问
解决方案:对类定义静态方法用以返回单实例。
作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。 常见网站计数器,应用程序日志应用
特点:单实例类只能有一个实例 单实例类必须自己给自己创建唯一实例 单实例类必须给所有其他对象提供这一实例
单例模式的宗旨在于确保某个类只有一个实例,并且为之提供一个全局访问点 通过隐藏构造器和提供对创建对象的单个访问点,单例模式就能够将类的职责集中于类的某个单个实例中。
单例模式,工厂,适配器模式
3.名称:策略
问题:如何设计变化但相关的算法或政策,才能使这些算法或政策具有可变的能力?
解决方案:在单独的类中分别定义每种算法/政策/策略,并且使其具有共同接口
策略基于多态实现,为了防止变异,策略通常由工厂创建
本质:分离算法,选择实现
4.名称:组合
问题:如何能够像处理非组合(原子)对象一样,多态地处理一组对象或者具有组合结构的对象呢?
解决方案:定义组合和原子对象的类,使它们实现相同的接口
组合模式的设计意图在于,让用户能够用统一的接口处理单个对象以及对象组合
将对象组合成树形结构以表示“部分-整体”的层次接口。组合模式使得用户对单个对象和组合使用具有一致性。
组合模式希望用户可以忽略与单个对象的不同,统一地使用组合结构中的所有对象。
5.名称:外观
问题:为了降低复杂性,往往将系统划分为若干个子系统,如何做到各个子系统之间的通信和相互依赖关系达到最小?
解决方案:对子系统定义唯一的接触点———使用外观对象封装子系统,外观对象提供了唯一和统一的接口,并负责与子系统构件进行协作。
外观模式为子系统的一组接口提供了一个一致的界面,定义了一个高层接口,这个接口使这一子系统更加容易使用
外观模式为设计粗糙或高度复杂的遗留代码提供一个简单的接口,使新系统与该接口对象交互
6.名称:观察者 发布-订阅
问题:不同类型的订阅者关注于发布者对象的状态变化或事件,并且想要在发布者产生事件时以自己独特的方式进行反应。此外发布者想要保持与订阅者的低耦合。
解决方案:定义订阅者或监听器接口,订阅者实现此接口。发布者可以动态注册关注其事件的订阅者,并在事件发生时通知他们。
观察者定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态发生变化时,会通知所有观察者对象,使其能够自动更新自己。
GoF分类
创建型:
抽象工厂,单实例
结构型:
适配器,组合,外观
行为型:
观察者,策略
设计模式六大原则:
开闭原则:
对扩展开放,对修改关闭
在程序需要进行拓展的时候不能去修改原有的代码,要实现热拔插的效果
需要使用接口和抽象类。
里氏代换原则:
任何基类可以出现的地方,子类一定可以出现
只有当衍生类替换掉基类,而软件单位的功能不受影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为
面向对象设计的基本原则之一,是继承复用的基石
依赖倒转原则:
高层模块不应该依赖低层模块,两者都应该依赖于其抽象
抽象不应该依赖细节
细节应该依赖抽象。
模块间的依赖通过抽象发生,实现类不发生直接依赖关系,其依赖关系通过接口或抽象类产生。
接口或抽象类不依赖于实现类
实现类依赖接口或抽象类
接口隔离原则:
使用多个隔离的接口比使用单个接口要好,降低依赖和耦合
迪米特法则:
一个实体应当尽量少与其他实体间发生相互作用,使得系统功能模块相互独立
合成复用原则:
尽量使用合成/聚合的方式,而不是使用继承。