# 设计原则与模式

在复杂系统的架构设计中引入设计原则与模式，能够极大降低复杂系统开发、和维护的成本

## 目录 <a href="#mu-lu" id="mu-lu"></a>

* 几个问题
* 为什么要学习设计模式
* 优良架构设计的具体指标
* 理解复杂系统
* 面向对象思想（指导复杂系统的分析、设计、实现）
* 设计原则
* 设计模式

### 几个问题 <a href="#ji-ge-wen-ti" id="ji-ge-wen-ti"></a>

* 单一职责原则的职责是什么
* 依赖倒置中的依赖是什么？（依赖注入DI，和 IOC 控制反转）
* 组合与聚合的区别是什么
* 贫血模型与充血模型的差异在什么地方
* 阅读开源项目代码时，单个方法可以理解，整体看不懂

### 为什么要学习设计模式 <a href="#wei-shen-me-yao-xue-xi-she-ji-mo-shi" id="wei-shen-me-yao-xue-xi-she-ji-mo-shi"></a>

* 有助于更快地读懂开源项目代码
* 自己编写通用组件、框架

设计模式可以帮助我们优化系统的设计，增强系统的健壮性，可扩展性

### 优良架构设计的具体指标 <a href="#you-liang-jia-gou-she-ji-de-ju-ti-zhi-biao" id="you-liang-jia-gou-she-ji-de-ju-ti-zhi-biao"></a>

* 可维护性
* 可读性
* 可扩展性
* 灵活性
* 简洁性
* 可复用性
* 可测试性

#### 可维护性 <a href="#ke-wei-hu-xing" id="ke-wei-hu-xing"></a>

* 在不破坏原有代码设计、不引入新的 bug 的情况下，能够快速地修改或者添加代码
* 代码分层清晰、模块化好、高内聚低耦合、遵从基于接口而非实现编程的设计原则

#### 可读性 <a href="#ke-du-xing" id="ke-du-xing"></a>

* 任何傻瓜都会编写计算机能理解的代码
* 好的程序员能够编写人能够理解的代码
* 代码只是偶尔拿出来给机器读一下，大多数时候都是给人读的

#### 可扩展性 <a href="#ke-kuo-zhan-xing" id="ke-kuo-zhan-xing"></a>

* 代码预留了一些功能扩展点，可以把新功能代码，直接插到扩展点上，而不需要因为添加一个功能而大动干戈，改动大量原始代码
* 对修改关闭，对扩展开放原则

#### 灵活性 <a href="#ling-huo-xing" id="ling-huo-xing"></a>

* 当我们添加一个新的功能代码的时候，原有的代码已经预留好了扩展点，我们不需要修改原有的代码，只要在扩展点上添加新的代码即可
* 当我们要实现一个功能的时候，发现原有代码中，已经抽象出了很多底层可以复用的模块、类等代码，我们可以拿来直接使用
* 当我们使用某组接口的时候，如果这组接口可以对应各种使用场景，满足各种不同的需求

#### 简洁性 <a href="#jian-jie-xing" id="jian-jie-xing"></a>

* 代码简单，逻辑清晰
* KISS 原则（Keep It Simple, Stupid）

#### 可复用性 <a href="#ke-fu-yong-xing" id="ke-fu-yong-xing"></a>

* 解耦、高内聚、低耦合、模块化、组件化

#### 可测试性 <a href="#ke-ce-shi-xing" id="ke-ce-shi-xing"></a>

* 单元测试友好 Mock

### 理解复杂系统 <a href="#li-jie-fu-za-xi-tong" id="li-jie-fu-za-xi-tong"></a>

* 系统思维
* 什么是复杂系统
* 系统复杂的原因
* 软件系统的复杂性
* 控制复杂性
* 面向过程与面向算法

#### 系统思维 <a href="#xi-tong-si-wei" id="xi-tong-si-wei"></a>

**什么是系统？**

* 系统是由一组实体和这些实体之间的关系所构成的集合，其功能要大于这些实体各个功能之各（涌现原则）
* 系统并不是其组成物的简单加总，而是这些组成物之间互动的产物 -- Russell Ackoff
* 整体大于其各部分之和 -- 亚里士多德

#### 什么是复杂系统 <a href="#shen-me-shi-fu-za-xi-tong" id="shen-me-shi-fu-za-xi-tong"></a>

由很多高度相关、高度互联和高度混杂的元素或实体所组成的系统

#### 系统复杂的原因 <a href="#xi-tong-fu-za-de-yuan-yin" id="xi-tong-fu-za-de-yuan-yin"></a>

* 我们总是有“更多的要求”（更多功能，更好性能，更健壮，更灵活）
* 我们要求系统能够与其它系统相互协作，相互连接
* 要用大量的信息来指定并描述

#### 软件系统的复杂性 <a href="#ruan-jian-xi-tong-de-fu-za-xing" id="ruan-jian-xi-tong-de-fu-za-xing"></a>

* 问题域的复杂性
* 管理开发过程的复杂性
* 软件系统中随处可能出现的灵活性
* 描述离散系统行为的问题

#### 控制复杂性 <a href="#kong-zhi-fu-za-xing" id="kong-zhi-fu-za-xing"></a>

* 算法分解
* 面向对象分解

### 面向对象思想（指导复杂系统的分析、设计、实现） <a href="#mian-xiang-dui-xiang-si-xiang-zhi-dao-fu-za-xi-tong-de-fen-xi-she-ji-shi-xian" id="mian-xiang-dui-xiang-si-xiang-zhi-dao-fu-za-xi-tong-de-fen-xi-she-ji-shi-xian"></a>

* 面向过程与面向算法
* 对象
* 类
* 抽象
* 封装
* 分解
* 分层

#### 面向过程与面向算法 <a href="#mian-xiang-guo-cheng-yu-mian-xiang-suan-fa" id="mian-xiang-guo-cheng-yu-mian-xiang-suan-fa"></a>

**面向对象**

它以类或对象作为组织代码的基本单元，并将封装、抽象、继承、多态四个特性，作为代码设计和实现的基石

**面向过程**

它以过程（可以理解为方法、函数、操作）作为组织代码的基本单元，以数据（可以理解为成员变量、属性）与方法相分离为最主要的特点。面向过程风格是一种流程化的编程风格，通过拼接一组顺序执行的方法来操作数据完成一项功能

#### 对象 <a href="#dui-xiang" id="dui-xiang"></a>

对象是一个实体，这个实体具有明确定义的边界（Boundary）和标识（Identity），并且封装了状态（State）和行为（Behavior）

* 对象具有明确定义的边界和标识
* 对象封装了状态和行为

#### 类 <a href="#lei" id="lei"></a>

类是一种抽象，它将相似的实体抽象成相同的概念，这种抽象过程强调相关特征而忽略其他特征

#### 抽象 <a href="#chou-xiang" id="chou-xiang"></a>

抽象（Abstraction）的过程就是**揭示事物区别于其他事物的本质特征**的过程，是一个分析和理解问题的过程，这个过程取决于使用者的目的，它应该包括使用者所感兴趣的那些职责问题，而忽略掉其他不相关的部分。从对象到类的过程就是抽象的过程，即将所见到的具体实体抽象成概念，从而可以在计算机世界中进行描述和对其采取各种操作

**最少承诺**

根据这个原则，对象的接口只提供它的基本行为，此外别无其他

**最少惊奇**

这个原则是指抽象捕捉了某个对象的全部行为，不多也不少，并且不提供抽象之外的惊奇效果或副作用

#### 封装 <a href="#feng-zhuang" id="feng-zhuang"></a>

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

* 抽象和封装是互补的概念：抽象关注的是对象可以观察到的行为，而封装关注这种行为的实现
* 抽象“帮助人们思考他们做什么”，而封装“让程序可以借助最少的工作进行可靠的修改”
* 封装在不同的抽象之间提供了明确的边界，因此导致了清晰的关注点分离
* 要让抽象能工作，必须将实现封装起来
* 明智的封装让可能改变的设计决策局部化
* 绝大多数情况下，只有当这个抽象的创造者显示地暴露出实现，而且客户愿意接受由此带来的额外的复杂性时，才会这样做

#### 分解 <a href="#fen-jie" id="fen-jie"></a>

分解（Decomposition）是指将单个大规模复杂系统划分为多个不同的小构件。分解后的构件通过抽象和封装等技术形成相对独立的单元，这些单元可以独立地设计和开发，从而实现化繁为简、分而治之，以应对系统的复杂系，降低软件开发成本

#### 分层 <a href="#fen-ceng" id="fen-ceng"></a>

分层（Hierarchy）是指面向不同的目标建立不同的抽象级别层次，从而在不同的抽象层次对系统进行分解，进一步简化对系统的理解
