设计模式6大原则简述

0、前言

  这一段时间一直在看设计模式,里面分多次提到几个设计原则,看了几次发现记不清楚,还是得自己动手总结一下吧,把书上的理论先理解写下来再说喽。

1、单一职责原则

  • 定义:不要存在多于一个导致类变更的原因,通俗的说就是一个类只负责一项职责。
  • 优点
    • 降低类的复杂度,一个类只负责一个职责,其逻辑一定会比一个类负责多项职责要简单,同时也易于维护
    • 提高类的可读性,提高系统的可维护性
    • 降低变更所带来的风险;系统的变更是必然的,如果单一职责原则遵守的好,那么当修改一个功能时可以显著降低对其他功能的影响

  虽说我们要遵守单一职责原则,但是也不是说死板的对每一个细节都严格遵守,也要视情况而定:如果一个类的逻辑非常简单且可以保证变化极小,此时可以在代码级别上违反单一职责原则;另外当一个类中方法很少时,也可以在方法的级别上违反这一原则。(这里我这么理解单一职责原则:分为两个层次,最高层次是类的层次,其次是方法层次上)但是如果一个类相对庞大,类中方法较多时,一定要遵守单一职责原则;宁愿在第一次扩展时花费精力完成重构,也要遵守这一原则,否则会给以后的扩展带来不可预估的灾难!

2、里式替换原则

  • 定义
    • 如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都替换为o2时,程序P的行为没有发生变化;那么类型T2是类型T1的子类型
    • 所有引用基类的地方必须可以透明的使用其子类的对象
    • 通俗的讲就是:一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别。也即在软件里面把父类都替换成他的子类,程序的行为没有发生任何变化。

  继承包含这样一层含义:父类中凡是已经实现好的方法(区别于抽象方法),实际上是在设定一系列的规则和契约,虽然它并不要求所有的子类都必须强制遵守这些规则,但是如果子类任意对这些非抽象方法进行重写,就会对整个继承体系造成破坏。里式替换原则主要就是想表达这一层含义。

  当然如果你非要重写父类的非抽象方法,这时应该采用这样的方式:原来的父类和子类都继承自一个更通用的基类,原有的继承关系去掉,转而采用依赖、聚合、组合等关系来替代。

  里式替换原则更通俗的说就是:子类可以扩展父类的功能,但是不能修改父类原有的功能;具体有以下4中含义:

  • 子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法
  • 子类可以增加自己特有的方法
  • 当子类的方法重载父类的方法时,方法的前置条件(形参)要比父类方法的输入方法更宽松
  • 当子类实现父类的抽象方法时,方法的后置条件(即方法返回值)要比父类更严格

  如果在开发中不遵循里式替换原则程序也照样跑的好好地,那么也没啥差别啊?这就错了,这样的后果就是你的代码出错的几率会大大的增加。

3、依赖倒转原则

  • 定义:抽象不应该依赖细节,细节应该依赖于抽象(说白了就是要针对接口编程,不要对实现编程);也即:
    • 高层模块不应该依赖于底层模块,二者都应该依赖于抽象;
    • 抽象不应该依赖于细节,细节应该依赖于抽象
  • 依赖倒转原则基于这样一个事实:相对于细节实现中的多变性,抽象的东西要稳定的多;以抽象为基础搭建起来的架构比以细节为基础搭建起来的架构要稳定的多。具体来说(.NET+C#),抽象一般指的是接口、抽象类,细节就是具体的实现类。使用抽象的目的是制定好规范和契约,而不要涉及具体的实现,把细节交给他们的实现类来完成。

  依赖倒转原则的核心就是面向接口编程,传递依赖关系有三种方式:接口传递、构造方法传递、setter传递(如果用过spring框架,那么对传递一定会很熟悉)。在实际的开发中我们主要通过以下几点来较好的遵守依赖倒转原则:

  • 底层模块尽量都要有抽象类或接口,或两者都有
  • 变量的声明类型尽量是抽象类或接口
  • 使用继承时要遵循里式替换原则

  遵循依赖倒转原则可以降低类之间的耦合性,提高系统稳定性,降低修改造成的风险。同时,采用依赖倒转原则给并行开发带来了极大的便利,参与开发的人越多、项目越庞大依赖倒转原则意义和好处就越明显。当前比较流行的TDD开发模式就是依赖倒置原则非常成功的应用。

4、迪米特法则

  • 定义(也叫最少知道原则)
    • 如果两个类不必直接通信,那么这两个类就不应当发生直接的相互作用。如果一个类需要调用另一个类的方法,可以通过第三方来转发这个调用
    • 一个对象应该保持对其他对象最少的了解

  通俗的来讲,就是一个类对自己以来的类知道的越少越好;也就是说对于被依赖的类来说,无论逻辑多么复杂,都应当把逻辑封装在内部,对外除了提供public方法之外,不泄露其他任何信息。再通俗来说:迪米特法则就是‘只与直接的朋友通信’。那么什么是直接的朋友呢:每个对象都会与其他对象有耦合关系,只要两个对象间出现耦合关系,我们就说两个对象之间是朋友关系。而耦合的方式有很多,依赖、关联、聚合、组合都是耦合关系;其中,我们称出现成员变量、方法参数、方法返回值中的类为直接朋友,而出现在局部变量中的类则是间接朋友关系。也就是说陌生的类最好不要作为局部变量的形式出现在类的内部。

  迪米特法则的初衷是降低类之间的耦合,但是凡事都有一个度,虽然可以避免与非直接类之间的通信,但是要通信就必须通过一个中介来发生关系;而过分的使用迪米特法则,就会产生大量这样的中介和传递类,导致系统的复杂度增加。所以在使用迪米特法则时,要反复权衡,既要做到结构清晰又要高内聚低耦合。

5、开放-封闭原则

  • 定义:一个软件实体(如类、模块、函数等)应该对扩展开放,对修改关闭;即可以扩展但是不能修改
  • 当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不能通过修改已有代码来实现变化。

  开放-封闭原则是面向对象设计中最基础的原则,它指导我们如何建立稳定、灵活的系统。但是他也是这几个模式中定义最为模糊的一个,在初接触它时,总给你一种无处下手的感觉,因为它太虚了。但是当把其他原则还有23中设计模式通读了一遍之后,我发现可以这么理解它:开放-封闭原则是战略,而其他的几个原则以及设计模式就是具体的战术;如何实现开放-封闭原则呢?要想实现一个战略,就必须要制定合适的战术:即,通过较好的遵守其他几个原则以及通过合适的设计模式,最终实现一个软件很好的开发-封闭原则。

※其他【接口隔离原则】

  客户端不应该依赖它不需要的接口,一个类对另一个类的依赖应该建立在最小的接口上。

  可以这么理解:如果接口过于臃肿,那么实现他的类不管用不用的到,都必须实现接口中所有的方法,这显然是不好的设计;这时候就需要遵循接口隔离原则对臃肿的接口进行拆分。他的原则就是:尽量建立单一的接口,尽量细化接口,接口中的方法尽量少。也就是说,我们要为各个类建立专用的接口,而不是试图去建立一个很庞大的接口共所有依赖他的类去调用。

  这里接口隔离原则与单一职责原则也有一定的区别,主要从以下方面来看:

  • 单一职责原则注重的是职责,而接口隔离注重的是对接口依赖的隔离;
  • 单一职责原则主要约束的是类,其次才是接口和方法,它主要针对的是程序中实现的细节;而接口隔离原则主要针对接口和抽象,针对程序框架的构建。

  但是在使用接口隔离原则时也一定要适度,一定要注意:

  • 接口尽量小,但是也要有限度。如果接口过小,会造成接口过多,而导致增加设计的复杂度。
  • 为依赖接口的类定制服务,只暴露给调用他的类所需要的方法,他不需要的方法则要隐藏起来。只有专注的为一个模块提供定制服务,才能建立最小的依赖关系。

  最后的这个接口隔离原则,我的看法就是:只是从更加细小的粒度上解释了单一职责原则。因此在这里放在最后的其他里面描述他。同时,这几个原则现在只是对照着定义还是自己很少的开发经历来理解,很多还无法清楚的理解和使用,后面还有很长的路需要走啊,加油!

原文地址:https://www.cnblogs.com/qingtian-jlj/p/6209157.html