Head First 面向对象分析与设计研读

Author Avatar
yujian95 4月 10, 2021
  • 在其它设备中阅读本文章

本文是对《Head First 面向对象分析与设计》一书的阅读总结。

导读

演示例子代码

大纲目录

image-20210407221202321

1 伟大的软件由此开始:良好应用程序的基石

什么是伟大的软件?

对客户友善的程序设计师说:

“伟大软件总是做客户要它做的事。因此即使客户突发奇想要以新方式使用软件,它还是能够交付客户预期的结果。”

符合需求的同时,经得起时间的考验。

面面对象的程序没计师说:

“伟大软件是面向对象的程序代码。因此没有一堆重复的程序代码,每个对象将自己的行为控制得很好。扩展也很容易,因为你的设计既稳固又灵活。”

设计良好,编码良好,易于维护、重用及扩展。

设计大师说:

“伟大软件使用千锤百炼过的设计模式与原则。你已经让你的对象保持低耦合( loosely coupled),让你的程序代码因禁止修改而关闭,因允许扩展而开放。这也有助于让程序代码更能重复利用。因此你不必重做每一件事,就可以一次又次地运用应用程序的部件。”

总而言之,伟大的软件是可扩展、低耦合;对修改关闭,对扩展开发。

伟大软件的简易三步骤

  1. 确认软件做客户要它做的事。

  2. 运用基本的OO原则来增加软件的灵活性。

  3. 努力实现可维护、可重用的设计。

伟大软件的简易三步骤

注意事项: 在满足需求的前提下,优化软件设计。别为了解决旧问题而产生新的问题。

  • 开发前,确定需求用例,测试驱动。
  • 用枚举替代String,从而实现编译时校验。
  1. 注意变量命名,体现功能。

  2. 让每个对象代表单一概念。

  3. 未使用的特性是无用赠品。

    如一个对象经常有空值/null的特性,可能有一个对象在做一种以上的工作。(可将该部分另外封装为一个子集)

封装:即让你将应用程序分成一组一组合乎逻辑的部件。

任何时候看到重复程序代码,就找个地方进行封装!

委托:一个对象将操作转交给另一个对象的动作,第二个对象代表第一个对象执行该操作。

委托是指当对象需要执行某項工作时不直接进行该工作,而是要求另一个对象代为处理(或者有时只是针对部分的工作)。如俩个对象比较时,不是在方法中考量俩个对象是否相等,而是通过委托某个对象的equals()方法进行比较。

低耦合:低耦合意味着应用程序里的各个对象各有特定工作要做,而且只做那項工作。因此应用程序的功能被分散给许多定义良好的对象,它们各自将单一工作做得很好。

1. 回顾

  • 当应用程序正常运作,客户是满意的。
  • 当应用程序持续正常运作,客户是满意的。
  • 当应用程序能够升级,客户是满意的。
  • 当应用程序能偶被重复利用,程序设计师是满意的。
  • 当应用程序具有灵活性,程序设计师是满意的。

2. 给客户所需之物:收集需求

每个人都想让客户满意。

需求究竟是什么?

  • 需求通常是一件特定的事,你可以测试那件事来确认你真的满足你需求。

  • 需求是单一的需要,详细说明特定产品或服务应该做的事。

  • 需求是系统为了正确运作所必须做的特定的事情。

系统运作的正确与否是由客户决定的。因此,假如你漏掉某项需求或者是客户忘了跟你提,系统还是没有正暗运作。

流程

  1. 确认你的软件做客户要它做的事。
  2. 倾听客户。谈到需求时最好让客户自己说。仔细听,注意系统需要做什么,稍后再整理出系统该如何做这些事。
  3. 创建需求列表。
  4. 为错误作规划。
  5. 替换路径出来系统的疑难问题。(当事情出错时,必须有替换路径达到系统的目标)
  6. 编写用例。
  7. 按照用例检查需求。
  8. 编写代码。

取得好需求的最佳方式就是了解系统应该做什么?

用例是什么?

  • 用例是人们调用一些步骤,而这些步骤会让系统做某事。
  • 用例是捕捉新系统或软件变更的潜在需求的技术。每个用例提供一个或多个场景,传达系统如何与终端用户或其他系统交互以实现特定目标。

用例的三个部分

  1. 清楚的价值。每个用例对于系统都必须有明确的价值,假如用例无助于客户实现目标,这个用例便没有什么价值。
  2. 起点与终点。每个用例都必须有明确的起点与终点。某件事开始此流程,然后要有条件指明此流程已完成。
  3. 外部启动者。每个用例由外部启动者开启。有时启动者是人,有时可能是系统外的任何事物。

2

3. 山可移,此情用不渝。。。现在情况有变:需求变更

需求总是时刻在变,而且解决这些改变让客户满意。

客户永远是对的。

当客户有新需求时,要靠你来改变应用程序以符合新需求。

主要路径:大部分时间想要遵循的路径。

替换路径:是包含在用例中的一个或多个步骤,这些步驟是可选的或提供替换性的方式通过用例。替换路径可能是增加到主要路径中的额外步骤,或提供步驟让你以完全不同于主要路径的方式到达用例的目的地。

4. 分析:将你的软件,带进真实世界

分析帮助你确保系统运作在真实世界的情境里。

以对客户、老板及自已合理的方式编写你的用例。分析及用例让你给客户、经理和其他开发者展示系统在真实世界的情境里如何运作。

委托保护你的对象免受软件中其他对象实现改变的干扰。

  • 用例里的名词通常是你需要编写的类,而且是系统的焦点。
  • 用例里的动词通常是系统中对象的方法。
  • 查看用例里的名词(与动词)以整理出类与方法的动作叫做文本分析

类图

  • 类图以很粗略的系统概述给你一个简单的方式来展示你的系统以及它的程序代码构想。
  • 类图里的属性通常对应到类的成员变量。
  • 类图里的操作通常代表类的方法。
  • 类图漏掉许多细节,如类的构造函数、某些类型信息以及类里操作的目的。

5. 良好的设计=灵活的软件

改变不可避免。

抽象类

  • 抽象类是实际的实现类的占位符。
  • 抽象类定义行为,而子类实现该行为。

每当你在俩个或者俩个以上的地方找到共同行为时,小心地将该行为抽象取到一个类里,然后以此共同类重用这项行为。

image-20210415223043992

类图解析

image-20210415223546175

image-20210415223450222

6. 解决大问题

看待大问题的最佳方式就是化整为零,将它视为许多单独的功能片段。

  • 通过封装变化之物让你的软件更有灵活性,更容易改变。
  • 对接口编码,而不是对实现,让软件容易扩展。
  • 取得良好需求的最佳方式就是去了解系统应该做什么。

功能(来着客户):关于系统需要做的某件事的高级描述。

需求(来着开发者):实现功能所需要的需求。

只要可以,就尽量把细节往后拖延。

用例图

image-20210416204049441

领域分析。识别、收集、组织及表示领域相关信息的流程,根据的是现有系统与其开发历程的研究,领域专家捕捉到的知识、潜在的理论以及领域里新兴的技术。

让我们以一种客户(Gary)能真正理解的方式把为游戏系统所想到的一切组合起来。这个流程称为领域分析,意思是以客户理解的术语描述问题。

7. 为混乱带来次序:架构

架构是系统的组织结构,包含分解开来的各个部件、它们的连通性、交互机制以及你在系统设计中使用的指导原则与决策。

第一个步骤总是确认应用程序做它该做的事。

  • 在小项目中,我们使用需求列表写下功能性;

  • 在大项目中,我们使用功能列表整理出那些事;

确定最重要的功能性片段是什么?

  • 它是系统本质的一部分吗?(最基础的东西)
  • 这到底是什么意思?(补充功能细节)
  • 我到底该如何做?

8. 原创性被高估:设计原则

开闭原则(OCP)

类应该允许为扩展而开放,禁止为修改而关闭。

  • 特定片段不允许修改,但是允许扩展。

不自我重复原则(DRY)

通过将共同之物抽取出来并置与单一地方来避免重复的程序代码。

  • 避免重复程序代码,保证单一性。

单一职责原则(SRP)

系统里的每一个对象应该具有单一职责,所有对象的服务都应该聚焦在实现该职责上。

  • 一个类只负责实现一类功能,改变时只有一个改变的理由。

Liskov替换原则(LSP)

子类型必须能够替换其基类型。

  • 委托:将特定工作的责任委派给另一个类或者方法。
  • 组合:将来自多个其他多个类的行为集合起来。
  • 聚合:组合,但没用突然的结束。(想在主要对象之外使用被组成对象的行为)

9. 软件终究是为客户服务:迭代与测试

先针对整体轮廓操作,接着迭代应用程序的每个片段,直到完成。

  • 功能驱动开发:挑出应用程序的特定功能,并且规划、分析及开发该功能,直到完成。
  • 测试驱动开发:挑出通过用例的场景并且编写程序代码以支持通过该用例的完整场景。

功能驱动开发

  • 在使用功能驱动开发时,一次做单一功能( feature);

  • 接着迭代,一次解决一个功能,直到你完成应用程序的整个功能性( functionality)。

测试驱动开发

  • 在用例驱动开发中,你操作通过用例的单一场景,接着再取出另一个场景并且完成它,直到所有场景被完成。

  • 然后再选代下个用例,直到所有用例都能运作。

俩种的区别

  • 每当你的客户急着要看结果时,你应该考虑采用功能驱动开发,从一个你已经完成一些工作的功能开始。

image-20210418135255492

良好的软件是通过迭代造就而成。分折、没汁、再一次选代,一次一次完成应用程序更小更小的部分。每当你迭代时,重新评估你的设计决策,假如它对你的设计合理,就别害怕改变。

契约式编程、防御性编程

  • 当你采取契约式编程时,你正在与客户的程序代码合作,以对你将如何处理有问題的状况达成协议。

  • 当你采取防御性编程时,你正在确保客户获得 “安全的” 响应,不管客户要什么。

10. OOA&D生命周期

  1. 功能列表:了解软件应该做什么?
  2. 用例图:思考软件将如何被使用。(不必思考细节)
  3. 分解问题:通过用例图,拆分为较小的功能性片段。(编写用例)
  4. 设计:圈选用例中名词(类)、动词(方法),初步建模,了解之间关系。
  5. 编码 -> 测试 -> 优化设计 -> 测试

用例反映使用性,功能反映功能性。

image-20210418140504082

附录1 本书遗珠

1. IS-A与HAS-A

  • IS-A:继承
  • HAS-A:组合或聚合

使用继承的时机是当一个对象的行为类似于另一个对象的行为时,而不只是因为IS-A关系成立。

image-20210418143423275

2. 反设计模式

  • 设计模式:是特定类型问题的经证实的解法,帮助我们以更容易理解、更好维护更具灵活性的方式结构化我们自己的应用程序

  • 反设计模式:是设计模式的反面。它们是问题共同的“坏”解法。这些潜藏的危险应该被识别出来并且被避免。

3. 缺陷密度

image-20210418143824328

image-20210418143843024

4. 顺序图

显示发生在参与者与系统间特定交互的一种视觉化方式。

image-20210418144007427

5. 状态图

通过显示不同状态( state)以及造成状态改变的动作( action)来描述系统的一部分,这对于以视觉化方式描述复杂的行为是非常棒的。

image-20210418144203828

image-20210418144225977

本站永久域名「 yujian95.cn 」,也可关注微信公众号「 编程图解 」找到我。
本文链接:http://yujian95.cn/post/notes/read/head-first-OOA-n-D.html