目录
类和对象
对象
对象的本质
状态
行为
【未深入】标识符
对象间的关系(重要)
链接
聚合
类
类的关系和对象的关系有何区别?
类和对象的区别和联系
创建高品质的类和对象
评价一种抽象的品质
选择操作
选择关系
选择实现
类和对象
对象
对象的本质
对象的思维是人类的早期思维。
什么是对象?什么不是对象?
从人类认知的角度,对象可以是以下的事物:
- 【对象可以是具体的】
- 感官上的可以感觉达到的
- 【对象可以是思想/概念上的】
- 人类用于辅助理解/加工 所 建构的概念;
- 思考,行动
真实世界的对象 VS 构造的对象
- 构造的对象属于什么东西?
- 【控制对象】
- 将事件过程组织起来的对象,负责与其它对象通信。
- 【对象的另一种定义方式】
- 对象可以被识别;
- 可以是真实的,也可以是抽象的;
- 在问题域中承担一定的角色;
关于对象理解的示例 —— 制造工厂(有明确的物理边界)
- 该示例中的对象的启发
- 示例中提到的对象都是可以触摸的/实际存在的;
- 【明确的边界】车床,自行车架
- 总体的需求
- 材料 制造工厂 得到各种商品(自行车架 & 飞机机翼)
- 制造工厂被划分成独立的车间
【具有启发意义】对象:(清晰的概念边界,代表不可触摸的事件或者过程)
- 什么叫做明确的概念边界?
- 【具体的体现】事件 & 过程
- 过程也可以看作是一种对象 将过程的理解对象化
- 【具体的体现】事件 & 过程
- 【示例】
- 化学处理过程 对象
- 有明确的概念边界;
- 订单 如何理解?
- 化学处理过程 对象
【对象 不是万能的】并不是所有的事物都是可以用对象来进行理解,进行刻画
- 【对象的定义】
- 对象的构成要素: 状态 , 行为, 标识符
状态
对象状态的定义:
- 对象状态的定义中包含了两大部分:
- 对象拥有的属性 (相对静态) 开阔视野的新观点。
- 事实上,java中的map,json使得对象的属性也是可增改的。 毕竟,现实中存在需要这种灵活的场景。
- 相应的属性对应的当前的值(通常是动态的)
- 对象拥有的属性 (相对静态) 开阔视野的新观点。
- 【注意】 接下来,要区分清楚 属性 & 属性的当前值。
- 状态只是抽象的一部分,不能表示抽象的全部含义。 为此需要考虑对象的行为。
理解对象的状态 —— 雇员记录
- 为何封装对象状态 是一个很好的工程实践? 这里面需要多大的技巧经验吗?
下面是优化后的抽象Employee:
- 通过权限机制 使得关键的信息被隐藏 从而达到封装的目的;
理解对象的状态 —— 自动售货机
对于自动售货机的描述
- 【理解】自动售货机 将现实生活中的步骤(人与人交互,进行购买)(可以当作对象来进行理解)进行了说明
行为
- 【对象在交互中发挥价值】对象不是孤立存在的。 对象通过合作,才能解决复杂的问题。
- 【行为的含义】状态改变 & 消息传递 动作
- 为何将行为定义为外部可见的? 行为主要是相对外界而言的。
对象行为在对象交互中体现,而在具体的语言中体现如下:
影响对象行为的因素:
- 传递给对象的消息
- 对象本身的状态
- 【示例】自动售货机 并不是你想要买,就能买的,这还取决于 自动售货机的内部逻辑 & 状态。
操作
- 为何是类提供给它的对象的一种服务。
- 因为操作的代码是类的对象所共有的。 所以它是属于类的。
- 而操作代码中的状态内容,是对象所独有的。 所以它是属于类的对象的。
角色和责任
- 【协议】作者对于协议的阐释很有启发性
- 一个对象的所有方法共同构成了它的协议。
- 【角色】对象行为空间的划分 形成了不同的角色
- 面具(接口)是对于对象角色的很好的比喻。
- 协议/抽象/分组后方法 定义了一种抽象与它客户之间的契约。
- 【在java中的体现】一个类实现了多个接口,本质上一个接口可以看作是一种角色。
责任更多的是从 目标 ,在系统中的位置 等外部视角来看待的:
- 责任意味着 为它支持的所有契约提供全部的服务。
- 【责任的变化性】
- 责任在对象不同生命周期可能不同;
- 面向不同客户的时候,责任可能是不同的。
对象像自动机
- 之前我的文章中,有对对象 & 自动机 进行过深入的探讨。
主动对象 & 被动对象
【未深入】标识符
标识符有这么重要吗?
对象间的关系(重要)
- 【站在系统角度】 独立的对象无法为系统做出贡献,必须通过协作的方式,才能参与到系统功能的运作中来。
- 生活中也是,只有人与人之间,进行互动协作,才能做成一些项目,做出一些成果。
- 【生动形象的比喻】飞机
- 有时候,我们与真正的理解之间,就差一个生动形象的比喻作为桥梁。
- 【对象间的关系】两种特别/重要的关系
- 链接
- 聚合
- 【注意】
- 对象间的关系 & 类之间的关系 是不同的
链接
- 【作用】建立对象结构上的关联。但是具体的传递信息,则是通过行为来进一步实现。
- 但是,行为是建立在相互知晓,相互关联基础之上的。 所以,结构是后续一些行为的前提。
- 【链接在实际中的体现】
- 某个对象A 拥有另一个对象的B的 引用。 意味着存在链接关系。
生动形象的示例:(水流控制系统)
- 【链接的作用】链接意味着途径/渠道, 操作/消息,可以通过这个途径进行传递。
- 【示例内容】
- 注意链接的方向; 意味着消息传递的主动方/被动方;
- 【分离关注是个什么东西?】 优化对象之间的链接结构;
- 以FlowController 为中心,避免 Value 与 DisplayPannle进行直接的交互; 能够产生较为简单的对象结构(远离图结构的形式) 更易理解 & 修改
在链接上的对象,可能的一般的行为:
聚合
- 【作用】提供 整体 导航到 部分的能力。
类
类的关系和对象的关系有何区别?
- 关系是什么?
- 关系是搭起了信息通信的桥梁。
- 【对象关系】 链接(关联),聚合
- 【类的关系】关联,继承,聚合,依赖?
- 【关系的辨别】
- 聚合是一种特殊的关联;
- (关联,继承,聚合)从静态结构角度考虑的问题。
- 依赖更多是从行为角度进行的考虑。
- 【关系的辨别】
类和对象的区别和联系
- 对象是类的实例;
- 类相对静态稳定,对象创建销毁频繁;
创建高品质的类和对象
- 【构建框架的一般方法】
- 找到最少稳定部分(通用) 针对该部分构建一个统一框架 适当添加框架细节 使用框架;
- 【示例】java中的集合框架;并发框架等等。
- 【关键问题】
- 如何寻找最少稳定部分?如何进行抽象?
评价一种抽象的品质
建议使用5个测量指标:
- 耦合
- 内聚
- 充分性
- 完整性
- 基础性
耦合
- 模块 & 模块 (对象 & 对象) 关联强度的度量。
- 【强耦合引发的问题】强耦合 系统变复杂 模块间高度相关 难以被独立的理解/修改/变化。
- 【面向对象】耦合与继承存在着矛盾的关系 (视情况选择平衡点)
- 继承 引入了严重的耦合; 理解子类有时候就必须理解父类,甚至祖先类。
- 继承帮我门理解抽象之间的共性。(其它:利于复用) 另一种形式的辅助理解(涉及到共性时)。
- 【反思自己的代码】
- 前后台分离时,尝试在通信时放入过多不必要的参数。 增加耦合性。
内聚
- 【作用】测量单个模块/对象 内 各个元素的联系程度。
- 【内聚的分类】
- 偶然性内聚(坏): 完全无关的抽象放到同一个类/模块中
- 功能性内聚(好):各元素 都支持 某个清晰的行为/功能。
- 【反思自己的代码】
- 【工具类】经常在写代码时,创建一个utils的工具类。这里面放了大量的方法内容,比如处理日期的,处理数组的。
- 按照内聚思想来看,utils这个工具类没有明确(界限清晰)的行为职责。当然,你可以用“工具”来概括这个工具类的功能,但是“工具”这个词太过于抽象,抽象的东西意味着含义是模糊的、界限不清楚的。
- 【工具类】经常在写代码时,创建一个utils的工具类。这里面放了大量的方法内容,比如处理日期的,处理数组的。
充分
- 【含义】类/模块 应该记录 某个抽象 足够多的特征, 允许有意义的、有效的交互。
- 【示例】Set(集合)
- 【错误】有删除,但是没有添加元素的操作。 不是充分的。
- 没有添加,那么删除便失去了意义。 并且,集合失去了容纳元素的功能。 破坏了 总功能/目标。
- 【错误】有删除,但是没有添加元素的操作。 不是充分的。
完整
简单/基础性
- 【示例】添加4个元素的操作(不是基础性操作),可由添加1个元素的操作构成。
选择操作
功能语义:
- 【细致的方法】 (风格)所有操作保持基础性 操作展现小、定义良好的行为
- 把握好基础性这一概念,构造时如何实现这种基础性?
- 【权衡】一个行为提取为1个方法,还是多个方法? 本质上,表达功能语义时功能拆解/封装程度。
- 【1个方法】接口简单,实现复杂;
- 【多个方法】接口复杂,实现简单;
一个类的行为应放入到哪个类之中?
- 【TODO】需要一个简单的例子辅助理解。
时间、空间语义(多线程)(暂不考虑)
选择关系
- 【能够访问】一个抽象能够访问另一个对象,并引用外部视图之中的资源。
- 【耦合】是度量可访问程度的重要指标。
- A与B耦合为0 意味着A不能访问B.
- 存在耦合 A能够访问B.
- 但是,耦合太严重时,又会造成理解/修改等方面的困难。 所以在处理耦合程度时,一定要做好权衡。
- 【耦合分类】人们把存在的耦合进行了分类。(参考mooc视频)
- 需要根据场景选择适当的耦合方式。
- 【示例】如通过消息队列来进行解耦。 耦合存在,但是程度比较低,通过引入中间环节,实现降低耦合程度。(否则,直接进行耦合,时间、空间上依赖度太强,降低灵活性)
- 【Demeter法则】用于指导选择的对象间关系时。
- 【效果/目的】创建 松耦合的类
- 【内容】类的方法不应该依赖于任何其它类的结构。& 发送消息时,操作有限的类。
类结构的常见分类(按照继承关系角度分类)
- 【宽而浅】森林 独立,缺少共性刻画
- 【窄而深】树 共性 理解时需要理解多个类
- 【平衡】
【关系的折中】继承、聚合、依赖
- 【经验】如果对象的行为超过了它的部分之和 相关类之间创建聚合关系(not 继承)
- 【示例】Car 类应该 继承、包含,还是使用名为Engine和Wheel的类? 包含
- “使用” 是什么意思?
【机制 && 可见性】
- 【基本思想】 对象间交互机制 对象间关系(可见性)
- 【理解】可见/可访问 发送消息
- 【可见方向】单向可见 or 双向可见
- 【示例:单向可见】汽车需知晓轮子的存在,但是轮子没必要知晓汽车的存在。
- 【示例:双向可见】管理者和被管理者需要相互知晓,因为要互发消息,而不是单向传递消息。
- 【可见的方式】链接 or 继承
- 【示例】机制如何影响关系/可见性?
- 【需求】制造计划种,物料(批次)进入制造车间等待处理。 接下来,看看机制(标红部分)如何影响关系?
- 【操作属于批次】车间能看到批次。 (车间调用批次的方法/行为,提供必要的车间信息(方法带参数))
- 【操作属于车间】批次能看到车间。 (批次调用车间的方法/行为)
- 【操作属于批次&车间】批次与车间 相互可见。(相互调用)
- 【需求】制造计划种,物料(批次)进入制造车间等待处理。 接下来,看看机制(标红部分)如何影响关系?
选择实现
- 【表示形式】多种,不能违反客户对功能的假定。
- 【示例】不同表示形式,提供不同的时间 && 空间 特性。
- 【需求】有一个Cone(圆锥)类,它包含一个Volume(体积)方法。调用该方法,返回体积的值。
- 我们已经利用字段保存了圆锥的高 && 底面的半径。
- 【实现的选择】将Volume保存为一个字段 ,还是 每次进行计算。
- 【Volume保存为字段】注重时间效率,牺牲部分空间效率;
- 【Volume每次计算】注重空间效率,牺牲时间效率。
- 【需求】有一个Cone(圆锥)类,它包含一个Volume(体积)方法。调用该方法,返回体积的值。