设计模式

182 阅读9分钟

参考:设计模式之美

设计模式学习导读

为什么要尽早学习并掌握设计模式

  1. 对面试中的设计模式相关问题
  2. 告别写被人吐槽的烂代码
  3. 提高复杂代码的设计和开发能力
  4. 让读源码、学框架事半功倍
  5. 为你的职场发展做铺垫
  6. 投资要趁早,这样我们才能尽早享受复利。同样,有些能力,要早点锻炼;有些东西,要早点知道;有些书,要早点读

如何评判代码质量

  1. 可维护性(maintainability):在不破坏原有代码设计、不引入新的 bug 的情况下,能够快速地修改或者添加代码
  2. 可读性(readability):code review 是一个很好的测验代码可读性的手段
  3. 可扩展性(extensibility):可扩展性实际是应用设计模式的最重要的目的
  4. 灵活性(flexibility):一段代码易扩展、易复用或者易用,我们都可以称这段代码写得比较灵活
  5. 简洁性(simplicity):思从深而行从简,真正的高手能云淡风轻地用最简单的方法解决最复杂的问题。这也是一个编程老手跟编程新手的本质区别之一
  6. 可复用性(reusability):减少重复代码的编写,复用已有的代码
  7. 可测试性(testability)

面向对象、设计原则、设计模式、编程范式、重构的关系

  1. 面向对象编程因为其具有丰富的特性(封装、抽象、继承、多态),可以实现很多复杂的设计思路,是很多设计原则、设计模式等编码实现的基础
  2. 设计原则是指导我们代码设计的一些经验总结,对于某些场景下,是否应该应用某种设计模式,具有指导意义。比如,“开闭原则”是很多设计模式(策略、模板等)的指导原则
  3. 设计模式是针对软件开发中经常遇到的一些设计问题,总结出来的一套解决方案或者设计思路。应用设计模式的主要目的是提高代码的可扩展性。从抽象程度上来讲,设计原则比设计模式更抽象。设计模式更加具体、更加可执行
  4. 编程规范主要解决的是代码的可读性问题。编码规范相对于设计原则、设计模式,更加具体、更加偏重代码细节、更加能落地。持续的小重构依赖的理论基础主要就是编程规范
  5. 重构作为保持代码质量不下降的有效手段,利用的就是面向对象、设计原则、设计模式、编码规范这些理论

面向对象

  1. 面向对象编程:是一种编程范式或编程风格。它以类或对象作为组织代码的基本单元,并将封装、抽象、继承、多态四个特性,作为代码设计和实现的基石
  2. 面向对象编程语言:是支持类或对象的语法机制,并有现成的语法机制,能方便地实现面向对象编程四大特性(封装、抽象、继承、多态)的编程语言

封装、抽象、继承、多态解决的问题

封装屏蔽代码复杂性,对外提供接口而不需要外部了解实现细节 抽象是指在具体的事务上抽离出本质特征,能代表一类事务,抽象让代码更具有扩展性 继承是解决代码复用问题 多态是指代码运行过程的多样性

面向对象与面向过程对比

面向对象:程序设计以对象为主体,是一个或多个对象自身的方法组合实现程序 面向过程:程序设计以过程为主体,通过对数据的加工处理实现程序

哪些代码看似是面向对象,实际是面向过程

常见的简单的mvc代码,controller,service,dao,model层的代码包含很多对象,但每个对象都没有实际领域含义,没有领域方法,仅仅是set,get方法或者上下层代码的调用

接口vs抽象类

接口:java中interface定义接口,接口方法通常没有具体实现,接口通过implement来实现,一个接口可以继承多个接口 抽象类:抽象类用abstract方法定义,包含未实现的方法,子类通过extend继承,只能继承一个抽象类

接口:通常代表一种行为,不包含成员变量 抽象类:与非抽象类的区别是存在abstract方法,定义了一种规范

为什么基于接口而非实现编程

1、这条原则,可以将接口和实现相分离,封装不稳定的实现,暴露稳定的接口。上游系统面向接口而非实现编程,不依赖不稳定的实现细节,这样当实现发生变化的时候,上游系统的代码基本上不需要做改动,以此来降低耦合性,提高扩展性。 2、越抽象、越顶层、越脱离具体某一实现的设计,越能提高代码的灵活性,越能应对未来的需求变化。好的代码设计,不仅能应对当下的需求,而且在将来需求发生变化的时候,仍然能够在不破坏原有代码设计的情况下灵活应对。

为什么多用组合少用继承

1、继承过深的代码不便于阅读 2、继承容易违背里氏替换原则 3、组合可以解决继承爆炸问题 4、组合实现最少知识原则

基于贫血模型的MVC架构违背OOP吗

违背,但是要看是否合适,简单的mvc架构没必要使用oop的原则去实现

设计原则

单一职责原则

1、职责单一的功能,更加内聚,耦合更少 2、职责单一的功能,更方便复用 3、职责单一的功能,方便阅读理解 4、职责单一的功能,功能修改,影响可控

对扩展开放,对修改关闭

1、添加一个新的功能应该是,在已有代码基础上扩展代码(新增模块、类、方法等),而非修改已有代码(修改模块、类、方法等)。 2、对扩展开放、对修改关闭”的代码的关键是预留扩展点 3、开闭原则的使用不是免费的,要权衡变化与不变,并持续重构

里氏替换跟多态的区别

1、里氏替换原则是对继承的一种限制 2、继承是多态的一种实现方式 3、里氏替换原则:子类在用法和语义上要能替换所有父类出现的地方

接口隔离原则的三种应用

1、一组api接口:给客户端提供接口时,不要提供客户端不需要的接口 2、函数中的接口:函数功能要单一,不在一个函数中做多个事情 3、oop中的接口:接口职责要单一,不要让实现类实现不需要的功能

控制反转、依赖反转、依赖注入的区别和联系

1、控制反转:对象的创建由代码控制改为框架控制 2、依赖反转:又称为依赖倒置原则,指高层模块不依赖底层模块,他们共同依赖一个抽象,抽象不要依赖具体的实现,具体实现依赖抽象。 3、依赖注入:对象依赖的成员变量由框架创建并自动注入

KISS、YAGNI原则

1、kiss:keep it simple and stupid,保持简单,不写难以理解的;不写团队不熟悉的;不重复造轮子 2、yagni:You Ain’t Gonna Need It,不要做过度设计

DRY原则-提高代码的重用性

1、dry:don‘t retry yourself,不写重复代码

2、代码重复,但是代码重复并不一定违反 3、逻辑重复,相同逻辑的方法,定义多个 4、语义重复,逻辑上不会执行的代码

5、消除代码复用性: 减少代码耦合 满足单一职责原则 模块化 业务与非业务逻辑分离 通用代码下沉 继承、多态、抽象、封装 应用模板等设计模式

迪米特法则

The Least Knowledge Principle,最小知识原则 含义:不该有直接依赖关系的类之间,不要有依赖;有依赖关系的类之间,尽量只依赖必要的接口(也就是定义中的“有限知识”)

规范与重构

什么情况下要重构、重构什么、如何重构

1、重构可分为两类,持续重构和大的重构 2、持续重构在代码修改过程中,碰到不合理的地方,根据代码规范和设计原则,利用设计模式进行重构 3、大的重构往往设计框架上的大改动,需要专门抽出一整块时间进行重写,要做好单元测试 4、小步快跑的方式进行重构,一次不要改动太多内容,改动之后要进行测试

保证重构不出错的技术手段

  1. 单元测试

代码的可测试性

  1. 测试代码是否容易编写
  2. 提高代码可测试的方法
    1. 依赖注入,代替创建对象
    2. 减少未决行为
    3. 减少使用全局变量
    4. 静态方法难以mock
    5. 继承复杂会导致难以mock父类属性
    6. 耦合严重会导致,注入对象繁多

通过封装、抽象、模块化、中间层等解耦代码

20条编程规范

通过ID生成器代码,学习如何发现代码质量问题

重构ID生成器

程序出错该返回啥?NULL、异常、错误码、空对象

重构ID生成器项目中的异常处理代码

设计模式与范式:创建型

单例模式

工厂模式

建造者模式

原型模式

设计模式与范式:结构型

代理模式

桥接模式

装饰器模式

设配器模式

门面模式

组合模式

享元模式

设计模式与范式:行为型

观察者模式

模板模式

策略模式

职责链模式

状态模式

迭代器模式

访问者模式

备忘录模式

命令模式

解释器模式

中介模式

开源实战

剖析JDK源码学习灵活应用设计模式

从Unix开源开发学习应对大型复杂项目开发

借Google Guava学习发现和开发通用功能模块

剖析Spring框架中的设计模式

MyBatis中的设计模式

项目实战

支持各种算法的限流框架

通用的接口幂等框架

自定义规则的灰度发布组件