设计模式杂谈

cheap talks

面相对象六原则

SOLID 5原则:单一职责,里氏代换,开闭原则,依赖倒置,接口隔离。

最小知识选择

SOLID 5原则

单一职责原则 SRP

名称:单一职责原则 SRP(Single Responsibility Principle)

定义

  • 宽泛的说

    • 对一个类而言,应该仅有一个引起它变化的原因。
  • 简而言之:

    • 一个类中应该是一组相关性很高的函数、数据的封装。

评价

  • 必要性:优化代码的第一步

  • 备受争议,但及其重要的原则。想和别人争执 怄气 吵架,就对着他的代码开始谈SRP吧

开闭原则 OCP

名称:开闭原则 OCP(Open Close Principle)

定义

  • 宽泛的说:软件中的对象(类,模块,函数等)应该

    • 对于 拓展 是开放的
    • 对于 修改 是封闭的
  • 简而言之:软件需要变化时,应尽量通过扩展的方式来实现变化而非修改已有代码来实现

    在实际开发中,修改原有代码和拓展新代码往往同时存在,为了确保原有软件模块的正确性应该尽量少地影响原有模块

具体做法:依赖里氏替换原则

  • 开闭原则和里氏替换原则相辅相成,通过LSP达到对拓展开放,对修改封闭的效果。

  • 程序一旦开发完成,程序中一个类的实现只应该因错误而被修改

  • 新的 或者 改变 的特性应该通过新建不同的类实现

    新的类可以通过继承的方式重用原类的代码,覆写父类的接口以应对变化。

评价

  • 优点

    • 让程序更稳定,更灵活

    • 否则,时,可能将错误引入到原有代码中,破坏原有系统。

  • 缺点:

    • 难以完全遵守,完全遵循开闭原则是很理想的情况

      因为在软件的生命周期中,变化、升级、维护等原因客观存在。不可避免有时要对软件原有代码进行修改

    • 另外也需要判断何时不遵守

      并不是说完全不修改原始类。在察觉到原有代码的“过时气味”时,应该尽早重构,以便代码恢复到正常的进化过程。这时继承等方式添加新的实现会导致类型的膨胀以及历史遗留代码的冗余。

里氏替换原则 LSP

名称:里氏替换原则 LSP(Liskov Substitution Principle)

定义

  • 宽泛的说:
    • 所有引用基类的地方必须能透明地使用其子类的对象。
  • 简而言之
    • 只要是父类能出现的地方子类就可以出现,并且替换为子类不会产生任何错误和异常
    • 使用者可能根本就不清楚使用的是父类还是子类
    • 子类应该可以实现基类的能力,并且能够完成对基类的替换
  • 核心原理——抽象
    • 面向对象语言的三大特点:继承 封装 多态
    • LSP 依赖于继承

具体实现

  • 运行时替换掉抽象,保证系统的拓展性、灵活性;

  • 开闭原则和里氏替换原则相辅相成,通过LSP达到对拓展开放,对修改封闭的效果。

评价

  • 优点

    • 代码重用
      • 减少创建类的成本。
      • 每个子类都拥有父类的方法和属性。
    • 提高代码可拓展性
  • 缺点

    • 继承是侵入式的,只要继承就必须拥有父类的所有属性和方法。

    • 子类代码冗余,灵活性降低。因为子类必须拥有父类的属性和方法。

依赖倒置 DIP

名称:依赖倒置原则(Dependence Inversion Principle)

定义

  • 宽泛的说:一种特定的解耦形式

    高层模块不依赖低层模块的具体实现,上下层之间应该依赖彼此的抽象。(高层模块指调用端,底层模块指具体实现类)

    • 抽象不应该依赖细节
    • 细节应该依赖抽象
  • 简而言之:模块间的依赖通过抽象产生

    • 依赖关系通过接口或抽象类产生
    • 实现类之间不发生直接的依赖关系
接口隔离 ISP

名称:接口隔离原则(InterfaceSegregation Principles)

定义

  • 宽泛的说:接口要简洁。客户端不应该依赖它不需要的接口
  • 简而言之:类间的依赖关系应该建立在最小的接口上

评价

避免了过多的细节暴露在客户端代码面前,否则会导致没有很好的隐藏实现,增加接口的使用难度。

用最小化接口隔离了实现类的细节,也促使我们将庞大的接口拆分到更颗粒度的接口当中,这使得系统具有更低的耦合性,更高的灵活性。

最小知识 LOD

名称:迪米特原则,最小知识原则(Least Knowledge Principle)

定义:

  • 宽泛的说

    • 一个对象应该对其他对象有最少的了解。
    • 对其他对象仅仅传递最少的信息
  • 简而言之:

    • 只与直接的朋友通信。

      • 一个类应该对自己需要耦合和调用的类,保持最少的认识

      • 类的内部如何实现与调用者或者依赖者没有关系。

        调用者或依赖着只需要知道它需要的方法即可。

    • 否则,类与类之间的关系越密切,耦合度越大。

      当一个类发生改变时,对另一个类的影响也越大。

关键技法

设计模式用到的一些关键的重构技法:

  • 静态 -> 动态
  • 早绑定 -> 晚绑定
  • 继承 -> 组合
  • 编译时依赖 -> 运行时依赖
  • 紧耦合 -> 松耦合

OMT图 描述对象的实现

OMT表示法:类是一个矩形

  • 类名 用黑体表示,第一行

  • 类方法/操作,第二行

  • 成员变量,第三行

抽象类/抽象操作,类名用斜体表示。

三角:继承

  • 虚线空心三角 实现类 --|> 抽象类:实现接口
  • 实线空心三角 子类 —|> 基类:继承
  • 存在的类—<|—新增的类(其中有两者的操作)—|>—混入类混入类(mixin class)要求多继承。
    • 给其他类提供可选择的接口或功能的类。
    • 混入类和抽象类一样不能实例化。

箭头:组合

  • 虚线箭头 A--->B :依赖

    • 类A中存在成员函数,需要B作为参数
  • 实线箭头 A—>B :关联

    • 类A中存在成员变量,类型为B
    • 类A中存在成员函数,B是函数返回值。

菱形:A的B的一部分

  • 虚线空心菱形 A--<>B:聚合

  • 虚线实心菱形 A--<黑>B :组合(更不可分割一些的关系)

代码 ----有褶角的框

出现在带有褶角的框中,虚线将该褶角框与代码连接

4种复用机制

4种复用机制:继承、组合、委托、模板

委托(独特与语言)java,C压根就没有。Cpp runtime lib 没有。C#倒是原生支持

server side: overload operator()加message queue

client side: lambda.

组合

组合 > 继承 随着系统演化得越来越依赖于对象组合,而不是类继承。

  • 重心从对一组固定行为的硬编码(hard-coding)转移为定义一个较小的基本行为集。

  • 行为可以被组合成任意数目的更复杂的行为。

继承

子类中有同样的字段,往上提。

类继承

类 class , 类型 type。

  • 一个对象对应一个类 class

  • 一个对象可以有多个类型 type —— 多继承,子类有多个基类、object就有多个type

  • 不同类class的对象可以有相同的类型 type —— 不同子类,可以继承自同一个基类。

接口继承

接口,即对象能够响应的请求的集合。对象的类型只和它的接口有关

根据抽象类中定义的接口操纵对象的好处:

  • 客户,无需知道使用对象的特定类型,知道对象有客户期望的接口就行。
  • 无需知道使用对象是用什么类实现的,知道定义接口的抽象类就行。

实现:

  • 纯接口继承:公有继承纯抽象类。

  • 纯实现继承 纯类继承:接近于私有继承。

  • 公有继承一个含有(纯)虚成员函数的类。C++中接口继承 的标准方法

委托、模板

个人之见

  • 二进制级别,编译单位的复用性 >= 源代码级别的复用(模板)

  • 模板 >> 复制粘贴

  • 运行时依赖 > 编译时依赖

设计模式

四要素

一个模式有四个基本要素:

  • 模式名(pattern name)
  • 问题(problem):描述了应该在何时使用。解释了问题和问题存在的前因后果。
  • 解决方案(solution):描述了设计的组成成分、它们之间的相互关系及各自的职责和协作方式。
  • 效果(consequence):描述了模式应有的效果,及使用模式应权衡的问题。

分类标准

常用分类

创建型结构型设计模式类型
Factory 模式被实例化的子类Bridge 模式对象的实现Template 模式对算法中的某些步骤
AbstactFactory 模式产品对象家族Adapter 模式针对对象的接口Strategy 模式算法
Singleton 模式针对一个类的唯一实例Decorator 模式对对象的职责,不生成子类State 模式对象的状态
Builder 模式如何创建一个组合对象Composite 模式一个对象的结构和组成Observer 模式对多个对象依赖于另外一个对象,而这些对象又如何保持一致
Prototype 模式针对被实例化的类Flyweight 模式对象的存储开销Memento 模式对一个对象中哪些私有信息存放在该对象之外,以及在对什么时候进行存储
Facade 模式对一个子系统的接口Mediator 模式对象间怎样交互、和谁交互
Proxy 模式如何访问一个对象;该对象的位置Command 模式何时、怎样满足一个请求
Visitor 模式某些可作用于一个(组)对象上的操作,但不修改这些对象的类
Chain of Responsibility 模式满足一个请求的对象链
Iterator 模式如何遍历、访问一个聚合的各元素
Interpreter 模式对一个语言的文法及解释

封装变化角度

对象创建组件协作单一职责对象性能类型接口隔离数据结构行为变化领域问题
Factory 工厂模式Template 模板模式Decorator 装饰器模式Singleton 单例模式Facade 门面模式Composite 组件模式Interpreter 解释器模式Command 命令模式Interpreter 解释器模式
Abstract Factory 抽象工厂Strategy 策略模式Bridge 桥接模式Flyweight 享元模式Proxy 代理模式Iterator 迭代器模式Visitor 观察者模式
Prototype 原型模式Observer / EventMediator 中介模式Chain of Resposiblity 责任链模式
BuilderAdaptor 适配器模式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值