「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战」
作者:汤圆
个人博客:javalover.cc
前言
本文介绍了设计模式中的七种原则,并配UML类图加以解释。
目录
- 单一职责原则
- 接口隔离原则
- 依赖倒置原则
- 里氏替换原则
- 开闭原则
- 迪米特法则
- 合成复用原则
正文
1. 单一职责原则
定义:一个类只做一件或一类事情
比如各种各样的交通工具,如果都放在一个类里,就会导致类的臃肿
- 反例:有一个交通工具类,里面包含了飞机、火车、公交的运行,导致概念混乱
- 正例:将交通工具类提升为一个接口,然后飞机类、火车类、公交类去实现交通工具类,实现解耦
2. 接口隔离原则
定义:一个类对另一个类(接口)的依赖,要建立在最小接口之上
比如类A只用到了类B的个别方法,则可以将类B拆分成多个类;
通过使用多个专门的接口,将一个大的接口拆分为多个明确独立的小接口。
比如有一个动物接口,包含方法有:飞翔、游泳;此时如果子类直接实现,那么就会导致接口臃肿;
比较好的办法就是将动物接口拆分成两个小接口,一个负责飞,一个负责游泳;
如果这两个小接口有共同点,则抽象一个父接口(比如动物都会吃)
- 反例:动物接口包含了飞和游,但是子类都只用到了一个方法,那么另一个方法就多余了。
- 正例:将动物接口拆分为两个小接口,分别包含飞和游
3. 依赖倒置原则
定义:要让细节依赖抽象,而不是抽象依赖细节
换句话说,就是要面向接口编程,不要面向实现编程,这样会更加灵活
- 反例:分别定义了Cat对象和Dog对象,Demo类依赖了Cat和Dog两个类
- 正例:只定义一个Animal对象,Demo类只依赖了Animal类
4. 里氏替换原则
定义:在使用基类的地方,要能够透明的使用子类的对象(即子类没用修改父类的已有方法)
子类继承父类时,尽量不要改动已有的方法,因为那样会增加耦合
如果实在需要修改,则将父类和子类都继承同一个类,这样就可以降低他俩之间的耦合
- 正例:这里的Demo类有个buy方法,将父类Animal作为参数,然后我们在调用时,既可以传入Cat,也可以传入Dog
5. 开闭原则
定义:一个实体应该对扩展开放(提供方),对修改关闭(使用者)
- 简单理解,就是对应用层来说,增加功能,不需要改动太大;但是对于实现层来说,就需要经常修改(扩展)
- 当软件需要变化时,尽量扩展类来实现,而不是修改现有类;因为修改现有类会影响依赖该类的地方,但是扩展的新类没有影响
- 正例:上面的第四点的UML就是正例,此时如果需要加一个动物类别,只需要新建一个类,然后实现Animal即可
6. 迪米特法则
定义:又叫最少知道原则,对自己依赖的类知道的越少越好
- 只和直接的朋友通讯,不和陌生的类通讯
- 直接的朋友:一个类以以下3种方式存在于另一个类种,则说明这俩类是直接的朋友
- 成员变量
- 方法的参数
- 方法的返回值
- 非直接的朋友:即陌生的类
- 类的方法中的局部变量就属于陌生的类
- 核心只是为了降低类之间的耦合,而不是完全消除耦合
- 反例:我们平时买水果,如果去果园买,会比较麻烦;比如买苹果要去苹果园,买香蕉要去香蕉园;
- 正例:这时就需要有一个商店,整合这些水果;然后我们就可以直接去商店买。这样一来,我们只需要依赖商店,不需要分别依赖各个水果园
7. 合成复用原则
定义:尽量使用合成/聚合,不要使用继承
- 依赖(Dependency): 和直接的朋友通讯,就说明这俩类有依赖关系 和陌生的类通讯,也是依赖关系;但是不满足迪米特法则 继承也属于依赖
- 聚合(Aggregation): 整体和部分的关系:整体和部分可以分离,比如电脑类、聚合了鼠标和键盘 通过成员变量引入类,通过setter赋值
- 组合(Composite): 整体和部分的关系:不可分离,比如人的类,组合了头 成员变量,定义时赋值
- 正例,这里就不列举了,上面的6个原则基本都有利用到这个原则。就是多复用,少继承