设计模式中的七大原则

937 阅读4分钟

「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战

作者:汤圆

个人博客:javalover.cc

前言

本文介绍了设计模式中的七种原则,并配UML类图加以解释。

目录

  • 单一职责原则
  • 接口隔离原则
  • 依赖倒置原则
  • 里氏替换原则
  • 开闭原则
  • 迪米特法则
  • 合成复用原则

正文

1. 单一职责原则

定义:一个类只做一件或一类事情

比如各种各样的交通工具,如果都放在一个类里,就会导致类的臃肿

  • 反例:有一个交通工具类,里面包含了飞机、火车、公交的运行,导致概念混乱
image-20211106191619177
  • 正例:将交通工具类提升为一个接口,然后飞机类、火车类、公交类去实现交通工具类,实现解耦
image-20211106191926210

2. 接口隔离原则

定义:一个类对另一个类(接口)的依赖,要建立在最小接口之上

比如类A只用到了类B的个别方法,则可以将类B拆分成多个类;

通过使用多个专门的接口,将一个大的接口拆分为多个明确独立的小接口。

比如有一个动物接口,包含方法有:飞翔、游泳;此时如果子类直接实现,那么就会导致接口臃肿;

比较好的办法就是将动物接口拆分成两个小接口,一个负责飞,一个负责游泳;

如果这两个小接口有共同点,则抽象一个父接口(比如动物都会吃)

  • 反例:动物接口包含了飞和游,但是子类都只用到了一个方法,那么另一个方法就多余了。
image-20211106193556024
  • 正例:将动物接口拆分为两个小接口,分别包含飞和游
image-20211107095945648

3. 依赖倒置原则

定义:要让细节依赖抽象,而不是抽象依赖细节

换句话说,就是要面向接口编程,不要面向实现编程,这样会更加灵活

  • 反例:分别定义了Cat对象和Dog对象,Demo类依赖了Cat和Dog两个类
image-20211107100542980
  • 正例:只定义一个Animal对象,Demo类只依赖了Animal类
image-20211107101114122

4. 里氏替换原则

定义:在使用基类的地方,要能够透明的使用子类的对象(即子类没用修改父类的已有方法)

子类继承父类时,尽量不要改动已有的方法,因为那样会增加耦合

如果实在需要修改,则将父类和子类都继承同一个类,这样就可以降低他俩之间的耦合

  • 正例:这里的Demo类有个buy方法,将父类Animal作为参数,然后我们在调用时,既可以传入Cat,也可以传入Dog
image-20211107102018359

5. 开闭原则

定义:一个实体应该对扩展开放(提供方),对修改关闭(使用者)

  • 简单理解,就是对应用层来说,增加功能,不需要改动太大;但是对于实现层来说,就需要经常修改(扩展)
  • 当软件需要变化时,尽量扩展类来实现,而不是修改现有类;因为修改现有类会影响依赖该类的地方,但是扩展的新类没有影响
  • 正例:上面的第四点的UML就是正例,此时如果需要加一个动物类别,只需要新建一个类,然后实现Animal即可

6. 迪米特法则

定义:又叫最少知道原则,对自己依赖的类知道的越少越好

  • 只和直接的朋友通讯,不和陌生的类通讯
  • 直接的朋友:一个类以以下3种方式存在于另一个类种,则说明这俩类是直接的朋友
    • 成员变量
    • 方法的参数
    • 方法的返回值
  • 非直接的朋友:即陌生的类
    • 类的方法中的局部变量就属于陌生的类
  • 核心只是为了降低类之间的耦合,而不是完全消除耦合
  • 反例:我们平时买水果,如果去果园买,会比较麻烦;比如买苹果要去苹果园,买香蕉要去香蕉园;
image-20211107112544773
  • 正例:这时就需要有一个商店,整合这些水果;然后我们就可以直接去商店买。这样一来,我们只需要依赖商店,不需要分别依赖各个水果园
image-20211107112634398

7. 合成复用原则

定义:尽量使用合成/聚合,不要使用继承

  1. 依赖(Dependency): 和直接的朋友通讯,就说明这俩类有依赖关系 和陌生的类通讯,也是依赖关系;但是不满足迪米特法则 继承也属于依赖
  2. 聚合(Aggregation): 整体和部分的关系:整体和部分可以分离,比如电脑类、聚合了鼠标和键盘 通过成员变量引入类,通过setter赋值
  3. 组合(Composite): 整体和部分的关系:不可分离,比如人的类,组合了头 成员变量,定义时赋值
  • 正例,这里就不列举了,上面的6个原则基本都有利用到这个原则。就是多复用,少继承