OOAD:面向对象分析与设计

1,835 阅读17分钟

领域驱动设计是综合软件系统分析和设计的面向对象建模方法,因此要想深入理解DDD,就必须先深刻理解OOAD(面向对象的分析和设计)。

面向对象分析与设计OOAD:对象模型

对象模型概述

面向对象技术建立在很好的工程基础之上,这个工程基础就是“开发对象模型”,简称“对象模型”。

对象模型包括:抽象、封装、模块化、层次结构、类型、并发和持久等原则,这些原则并不是对象模型专属的,只是对象模型把这些要素以一种互相配合的方式结合起来罢了。

使用面向对象模型有哪些好处呢?

首先,使用对象模型帮助我们探索基于对象和面向对象编程语言的表达能力。

其次,利用对象模型不仅鼓励软件的复用,还鼓励设计的复用。

最后,使用对象模型将得到构建在稳定的中间状态上的系统,这样的系统更适合变化,这也意味着,这样的系统可以随着时间进化,而不是当需求进行大的修改的时候就要抛弃原有的设计完全重新设计。

下面对对象模型相关的方法(OOA、OOD、OOP)和要素(七大原则:抽象、封装、模块化、层次结构、类型、并发和持久)进行简单介绍,方便你进行理解。

面向对象编程OOP

什么是面向对象编程?

面向对象编程是一种实现方法,在这种方法中,程序被组织成许多组互相协作的对象,每个对象代表某个类的一个实例,而类则属于一个通过继承关系形成的层次结构。

这个定义有3个要点:

1、利用对象作为面向对象编程的基本逻辑构建块。

2、每个对象都是某个类的一个实例。

3、类与类之间可以通过继承关系联系在一起。

一个程序如果不满足以上任何一点,那么这个程序就不是面向对象的程序。

面向对象设计OOD

那么什么是面向对象设计呢?

面向对象设计是一种设计方法,包括面向对象分解的过程和一种表示法,这种表示法用于展现被设计系统的逻辑模型金额物理模型、静态模型和动态模型。

这个定义中有两个要点:

1、面向对象设计导致了面向对象分解。

2、面向对象设计使用了不同的表示法来表达系统逻辑设计(类和对象结构)和物理设计(模块和处理架构)的不同模型,以及系统的静态特征和动态特征。

面向对象分析OOA

那么什么是面向对象分析呢?

面向对象分析是一种分析方法,这种方法利用从问题域的词汇表中找到的类和对象来分析需求。

OOA、OOD和OOP之间的关系是:

面向对象分析的结果可以作为面向对象设计的模型,面向对象设计的结构可以作为蓝图,利用面向对象编程的方法实现一个系统。

对象模型要素

对象模型有7个要素,其中包含4个主要要素和3个次要要素。

面向对象模型有4个主要要素,是否包含这4个要素决定了一个模型是否为面向对象的:

1、抽象

2、封装

3、模块化

4、层次结构

面向对象模型还有3个次要要素,所谓次要要素,表示这些要素是面向对象模型有用的的组成部分,但是并不是本质的:

1、类型

2、并发

3、持久

抽象

从人类认识世界的角度来讲,抽象是我们人类处理复杂性的基本方式。抽象来自我们对于真实世界中特定对象、场景或处理的相似性的认知, 并且我们决定关注这些相似性的同时忽略不同之处。

抽象就是对一个系统的一种简单的描述或指称,强调系统的某些细节或属性,同时忽略另一些细节或属性。因此,好的抽象就是强调了对用户重要的细节,而抑制了哪些暂时的非本质的细枝末节。

对于对象模型来讲,抽象描述了一个对象的基本特征,可以将这个对象与所有其他类型的对象区分开来,因此提供了清晰定义的概念边界,它与观察者的视角有关。

抽象关注一个对象的外部视图,所以可以分离对象的基本行为和它的具体实现。行为与实现的分界就是所谓的“抽象壁垒”,它是通过应用“最小承诺原则”来达成的。

最小承诺原则要求对象的接口只提供它的基本行为,此外别无其他。

抽象的类型:

实体抽象

动作抽象

虚拟机抽象

偶然抽象

抽象的例子:智能音箱。

现在智能设备日益普及,包括传统的音响,也被互联网+来起来,成为IoT设备。

基础音响

抽象: 音箱

重要特征: 声音 位置

责任: 播放声音

抽象: 智能音箱

重要特征: 声音 位置 网络

责任: 收集声音 播放声音 连接网络

封装

封装是什么?

封装是一个过程,它分割构成抽象的结构和行为的元素。封装的作用是分离抽象的概念接口及其实现。

封装是一个与抽象互补的概念:

1、抽象关注对象可以观察到的行为,而封装关注这些行为的实现。

2、封装通常是通过信息隐藏来实现的,信息隐藏就是将那些不涉及对象本质特征的秘密都隐藏起来的过程,通常对象的结构和其方法的实现都是隐藏的。封装要达成的目的是:复杂系统的每一部分都不应该依赖于其他部分的内部细节。

3、封装在不同的抽象之间提供了明确的边界,因此导致了清晰的分离关注。

模块化

模块化是什么?

模块化是一个系统的属性,这个系统被分解为一组高内聚、低耦合的模块。

将一个程序分割到一些不同的组件中,可以在某种程度上减少它的复杂性。模块化将程序划分为一些模块,这些模块可以独立地编译,但又与其他模块有联系。所谓高内聚,就是要将逻辑上相关的抽象放在一起;所谓低耦合,就是要减少模块间的依赖关系。

层次结构

层次结构是什么?

层次结构是抽象的一种分级或排序。

在复杂系统中,最重要的两种层次结构是它的类结构(“是一种”层次结构,如继承)和对象结构(“组成部分“层次结构,如聚合)。

继承基本上定义了类之间的关系,在这种关系中,一个类共享了一个或多个类(分别对应单继承和多继承)中定义的结构或行为。

“是一种”层次结构说明了一般/特殊关系(如:哺乳动物/猫),而“组成部分“层次结构则,描述了聚合关系。

继承和聚合结合在一起的功能是强大的:聚合允许对逻辑结构进行物理分组,而继承允许这些共同的部分在不同的抽象中被复用。

类型

什么是类型?

类型是关于一个对象的类的强制规定,这样一来,不同类型的对象不能互换使用,或者至少它们的互换使用会受到非常严格的限制。

类型匹配的概念是类型概念的核心。类型一般分为强类型和弱类型。

强类型语言有一些重要的好处:

1、通过类型检查,可以减少程序以神秘的方式崩溃。

2、大多数系统中,从编辑到编译再到最终调试的过程非常繁琐,所以早起的错误检查非常有必要。

3、类型的声明有助于为程序编写文档,方便程序与外部交互的规范化。

4、通过声明类型,大部分编译器可以生成更有效率的目标代码。

5、在实践中,强类型所带来的安全性,常常能够补偿不使用无类型语言所带来的灵活性损失,特别是在大规模编程中。

除了强类型与弱类型,还有静态类型和动态类型之分。

静态类型指的是所有变量及表达式的类型,在编译时就已经固定了,因此也叫静态绑定或早期绑定。动态类型意味着所有变量或表达式的类型直到运行时刻才知道,因此也叫迟后绑定。

多态是动态类型和继承互相作用时出现的一种情况。多态说明,一个名字或者一个变量声明,可以代表许多不同类的对象,这些类具有某个共同的超类。

并发

什么是并发?

并发是一种属性,它区分了主动对象和非主动对象。

有时候我们需要系统同时处理许多不同的事件,有时候我们需要做的计算量大大超出了单个处理器的能力,这些情况下,我们就要考虑用一组分布式的计算机来实现目标,或者利用多任务。这就是需要并发的原因。

持久

软件中一个对象会占用一定的空间,并在一定的时间内存在。

持久解决的不只是数据生命周期的问题。

什么是持久?

持久是对象的一种属性,利用这种属性,对象跨越时间(例如,当对象的创建不存在的时候,对象仍然存在)和空间(例如,对象的位置从它被创建的地址空间移开)而存在。

面向对象分析与设计OOAD:类与对象

对象的本质

识别物理对象是人类早期就具有的能力,比如婴儿刚出生不久就能识别周围人的面孔。

从广义上讲,一个对象反映了某一部分真实存在,因此它是在时间和空间存在的某种东西。

而在软件开发中,一个对象是一个具有状态、行为和标识符的实体。结构和行为类似的对象定义在他们共同的类中。实例和对象这两个术语可以互换使用。

对象的状态

对象的状态包括这个对象的所有属性(通常是静态的)以及每个属性当前的值(通常是动态的)。

一个属性是一种内在的独特的特征、特点、品质或特性,使一个对象区别于其他对象。

属性通常是静态的,因为这样的特征是不可更改的,是对象的根本本质。但也有例外情况,因为在某些情况下对象的属性也会改变。

每个对象都有状态,系统中所有对象都封装了某种状态,系统中的所有状态也都由对象所封装,每个对象都会在物理世界或者计算机内存中占据一定的空间。虽然有些对象的属性是相同的,但是它们并不会共享这些空间。

对象的行为

没有对象是一座“孤岛”,当然,孤岛也是一个对象,这里要强调的是对象不是孤立存在的,对象与对象之间会相互操作。

行为是对象在状态改变和消息传递方面的动作和反应方式。换言之,对象的行为代表了它外部可见的活动。因此,状态的定义可以改进为,一个对象的状态代表了它的行为的累积效果。

一个对象的行为包括了其操作的总和。一个操作代表了一个类提供给它的对象的一种服务。

在实践中,我们发现一个客户通常执行一个对象的5种操作。

其中常见的操作有3种:

  • 修改操作:更改一个对象的状态的操作。

  • 选择操作:访问一个对象的状态但并不更改这个状态的操作。

  • 遍历操作:以一种定义良好的方式访问一个对象的所有部分的操作。
    另外两种公共的操作:

  • 构造操作:创建一个对象并初始化它的状态的操作。

  • 析构操作:释放一个对象的状态饼干销毁对象本身的操作。

一个对象所有方法共同构成了它的协议。因此,一个对象的协议定义了对象允许的行为封装,构成了这个对象完整的静态试图和动态视图。

责任意味着表达对象的一种目标以及它在系统中的位置。一个对象的责任是它为支持的所有契约提供的全部服务。

对象的标识符

标识符是对象的一个属性,它区分了这个对象与其他所有对象。

每个对象的唯一标识符是在对象的整个生命周期中都保持不变的,及时它的状态改变了也是如此。

对象之间的关系

单个对象的作用是非常有限的,对象通过与其他对象协作,从而使得系统更为强大。

在面向对象分析与设计中有两种重要的关系,一个是链接,一个是聚合。

链接是两个对象之间物理上或者概念上的联系,一个对象通过与其他对象的链接,与其他对象协作。

链接代表了具体的关联,通过这种关联,一个对象(客户)请求另一个对象(服务提供者)的服务,或者通过这种关联从一个对象导航到另一个对象。

链接表明了一种从端到端的关系或者客服/服务提供者的关系,而聚合则表明了一种整体/部分层次结构,提供了从整体(也被称为聚合体)导航到它的部分的能力。

类的本质

在面向对象分析与设计的上下文中,我们将类定义为:

类是一组对象,它们拥有共同的结构、共同的行为和共同的语义。

一个对象就是类的一个实例。类是对象的抽象。

抽象品质的评判标准

如何判断某个类或者对象的设计是良好的呢?

常用的有5个测量指标,分别是:

  • 耦合

  • 内聚

  • 充分性

  • 完整性

  • 基础性

耦合是来自结构化设计的一个概念。耦合是一个模块和另一个模块之间建立起的关联强度大测量。强耦合使得系统变得复杂,如果模块与其他模块高度相关,它就难以独立地被理解、变化或者修正。通过系统设计,使得模块之间的耦合降至最弱,可以降低复杂性。

内聚的思想也来自结构化设计。内聚测量了单个模块(单个类或者单个对象)内各个元素的联系程度。最不希望出现的内聚是偶然性内聚,也就是将完全无关的抽象塞进同一个类或者模块中。最希望出现的内聚就是功能性内聚,即一个类或者模式的各个元素一同工作,提供某种清晰界定的行为。

一个类或模块应该是充分的、完整的、简单的。所谓充分,指的是类或者模块应该记录某个抽象足够多的特征,从而允许有意义的、有效的交互;否则,将使得该组件变得无用。所谓完整,指的是类或模块的接口记录了某个抽象的全部有意义的特征。完整性是一种主观判断,为某个抽象提供全部有意义的操作可能让用户不知所措,通常也是不必要的,因为许多高级的操作可以由低级的组合做到,因此类和模块应该具有基础性。基础性操作就是只有访问该抽象的底层表现形式才能够有效地实现那些操作。

举例来说,如果设计一个集合类,只有删除元素的操作而没有添加,那么这个抽象的设计就是不充分、不完整的;向一个集合添加一个元素是一项基础性操作,因此需要知道底层表现形式,而向一个集合添加4项元素的操作就不是基础性操作,可以在已有的基础性操作上实现。

面向对象分析与设计OOAD:统一建模语言

画图的动作并不是分析与设计的要点,一张图示只是记录系统行为的一种说明,或者一种架构的愿景与细节。系统构想形成的唯一场所是设计者的头脑,当这种设计随着时间展开之时,不论是记录在白板上还是餐巾纸上,跟记录在任何高科技的仪器上是一样的。

拥有一种定义良好的、富有表现力的表示法对于软件开发过程很重要。

首先,标准的表示法可以让分析师或开发者能够描述一个场景,阐明一种架构,然后无歧义地表达出来。

其次,好的表示法消除了大脑不必要的工作,让大脑能够集中考虑更高级的问题。

最后,一种富有表现力的表示法能够利用自动化的工具,消除关于这些决定的许多繁琐的一致性和正确性检查。

统一建模语言(UML)是分析、说明和设计软件系统的主要建模语言。

UML图可以分为两大类:结构图和行为图。

结构图用于展示系统中元素的静态结构,它们描述系统的架构组织、系统的物理元素、系统的运行时刻配置和业务中领域相关的元素等。

结构图包括:

  • 包图

  • 类图

  • 组件图

  • 部署图

  • 对象图

  • 组合结构图

结构图常常与行为图一起使用来描述系统等某个方面,行为图用于描述问题的动态行为语义或它的实现。

行为图包括:

  • 用例图

  • 活动图

  • 状态机图

  • 交互图

  • 序列图

  • 通信图

  • 交互概述图

  • 时间图

随着系统开发的推进和成熟,你的系统模式可能代表了不同的细节层次。

概念模型记录了系统存在的领域实体以及它们与系统中其他领域实体的关系。概念层的建模是利用业务领域的术语完成的,应该是与技术无关的。

系统的逻辑视图利用了概念模型中创造的概念,建立起关键抽象和机制的意义,并确定系统的架构和整体设计。

系统的物理模型描述了系统实现的具体软件和硬件构成,物理模型是技术相关的。

对于某个项目来说,随着时间的推移,系统的设计将由概念成熟发展到逻辑成熟,最后发展到物理成熟:概念模型(业务领域术语)-->逻辑模型(系统架构设计)-->物理模型(软件硬件构成)。