• 设计模式六大原则


    非原创,摘抄总结于网上多篇文章

    ps:都是一些定义说明,比较抽象

    1、单一职责原则

    定义:

      单一职责原则又称为单一功能原则,即不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。

    原理:

      如果一个类承担的职责过多,就等于把这些职责耦合在一起了。一个职责的变化可能会削弱或者一直这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当发生变化时,设计会遭受到意想不到的破坏。而如果想要避免这种现象的发生,就要尽可能的遵守单一职责原则。此原则的核心就是解耦和增强内聚性。

    问题由来:

      T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障。也就是说职责P1和P2被耦合在了一起。

     产生原因:

      没有任何的程序设计人员不清楚应该写出高内聚低耦合的程序,但是很多耦合常常发生在不经意之间,其原因就是:职责扩散,因为某种原因,某一职责被分化为颗粒度更细的多个职责了。

    解决办法: 

      遵守单一职责原则,将不同的职责封装到不同的类或模块中

    优点:

    • 可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多;
    • 提高类的可读性,提高系统的可维护性;
    • 变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。

    2、里氏替换原则

    定义:

      里氏替换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏替换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。(即假若父类是某功能模块的零件,使用子类代替父类并且功能模块能正常运行)【子类实例能够替换父类实例】

      继承包含这样一层含义:父类中凡是已经实现好的方法(相对于抽象方法而言),实际上是在设定一系列的规范和契约,虽然它不强制要求所有的子类必须遵从这些契约,但是如果子类对这些非抽象方法任意修改,就会对整个继承体系造成破坏。而里氏替换原则就是表达了这一层含义。

            继承作为面向对象三大特性之一,在给程序设计带来巨大便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加了对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能会产生故障。

    实际情况:

      在实际编程中,我们常常会通过重写父类的方法来完成新的功能,这样写起来虽然简单,但是整个继承体系的可复用性会比较差,特别是运用多态比较频繁时,程序运行出错的几率非常大。如果非要重写父类的方法,比较通用的做法是:原来的父类和子类都继承一个更通俗的基类,原有的继承关系去掉,采用依赖、聚合,组合等关系代替。

    通俗含义:

    子类可以扩展父类的功能,但不能改变父类原有的功能

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

    3、依赖倒置原则

    定义:

      高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。

    区别:

      面向过程的开发,上层调用下层,上层依赖于下层,当下层剧烈变动时上层也要跟着变动,这就会导致模块的复用性降低而且大大提高了开发的成本。

      面向对象的开发很好的解决了这个问题,一般情况下抽象的变化概率很小,让用户程序依赖于抽象,实现的细节也依赖于抽象。即使实现细节不断变动,只要抽象不变,客户程序就不需要变化。这大大降低了客户程序与实现细节的耦合度。

    问题由来:

      类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。

    解决方案:

      将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。

      依赖倒置原则基于这样一个事实:相对于细节的多变性,抽象的东西(接口或抽象类)要稳定的多。以抽象为基础搭建起来的架构比以细节(具体的实现类)为基础搭建起来的架构要稳定的多。

    传递依赖关系有三种方式,接口传递、构造方法传递、set方法传递

    编程要求:

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

    4、接口隔离原则

    ISP(ISP--Interface Segregation Principle)

    定义:

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

    问题由来:

      类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类A和类B来说不是最小接口,则类B和类D必须去实现他们不需要的方法。

    解决方案:

      将臃肿的接口I拆分为独立的几个接口,类A和类C分别与他们需要的接口建立依赖关系。也就是采用接口隔离原则

    因此:

      建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。也就是说,我们要为各个类建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。4

    注意:

    • 接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。
    • 为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。
    • 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。

    5、迪米特法则

     定义:

      迪米特法则(Law of Demeter)又叫作最少知识原则(Least Knowledge Principle 简写LKP),就是说一个对象应当对其他对象有尽可能少的了解,不和陌生人说话。英文简写为: LoD.

      通俗的来讲,就是一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类来说,无论逻辑多么复杂,都尽量地的将逻辑封装在类的内部,对外除了提供的public方法,不对外泄漏任何信息。另一种说法:只与直接朋友通讯

    直接朋友:

    出现成员变量、方法参数、方法返回值中的类

    非直接朋友:

    局部变量中的类

    问题由来:

      类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。

    解决方案:

      尽量降低类与类之间的耦合。

    注意:

      迪米特法则的初衷是降低类之间的耦合,由于每个类都减少了不必要的依赖,因此的确可以降低耦合关系。但是凡事都有度,虽然可以避免与非直接的类通信,但是要通信,必然会通过一个“中介”来发生联系。过分的使用迪米特原则,会产生大量这样的中介和传递类,导致系统复杂度变大。所以在采用迪米特法则时要反复权衡,既做到结构清晰,又要高内聚低耦合。

    6、开闭原则

    定义:

      一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

    问题由来:

      在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有代码进行修改时,可能会给旧代码中引入错误,也可能会使我们不得不对整个功能进行重构,并且需要原有代码经过重新测试。

    解决方案:

      当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。

    总结:

      用抽象构建框架,用实现扩展细节。因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节,我们用从抽象派生的实现类来进行扩展,当软件需要发生变化时,我们只需要根据需求重新派生一个实现类来扩展就可以了。当然前提是我们的抽象要合理,要对需求的变更有前瞻性和预见性才行。

      前面说的5项原则,恰恰是告诉我们用抽象构建框架,用实现扩展细节的注意事项而已:单一职责原则告诉我们实现类要职责单一;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合。而开闭原则是总纲,他告诉我们要对扩展开放,对修改关闭。

  • 相关阅读:
    挖地雷——线性dp
    hdu6376 度度熊剪纸条-----01背包
    Problem
    UVa 10635
    Vjudge_题目分享_A -> 线性Dp排列木棍 ( Dilworth定理应用
    洛谷日报 & 原来博客(转载)
    使用.net6 WebApplication打造最小API
    k8s笔记——NodePort暴露nginx-controller实现https自动跳转自定义nodePort端口
    通过Dapr实现一个简单的基于.net的微服务电商系统(十七)——服务保护之动态配置与热重载
    通过Dapr实现一个简单的基于.net的微服务电商系统(十六)——dapr+sentinel中间件实现服务保护
  • 原文地址:https://www.cnblogs.com/phpstudy2015-6/p/6729725.html
Copyright © 2020-2023  润新知