设计模式——七大软件架构设计原则

发布于:2022-12-05 ⋅ 阅读:(778) ⋅ 点赞:(0)

一、开闭原则

  1. 概念:
           ~~~~~~        一个软件实体,如类、模块和函数,应该对扩展开放,对修改关闭。
           ~~~~~~        所谓开闭,也正是对扩展和修改两个行为的一个原则。
           ~~~~~~        核心:面向抽象编程:用抽象构建框架,用实现扩展细节,提高软件的可复用性和可维护性
  2. 例子:利用IOC框架(Spring)动态创建对象
    在这里插入图片描述
           ~~~~~~       

二、依赖倒置原则(Dependence Inversion Principle)

  1. 概念:
           ~~~~~~        高层模块不应该依赖底层模块
           ~~~~~~        两者都应该依赖其抽象,抽象不应该依赖其细节
           ~~~~~~        细节应该依赖抽象:
           ~~~~~~               ~~~~~~        1) 低层模块:不可分割的逻辑
           ~~~~~~               ~~~~~~        2) 高层模块:逻辑的再组装
  2. 什么是抽象:
           ~~~~~~        抽象就是指接口或抽象类,两者都是不能直接被实例化的
  3. 什么是细节:
           ~~~~~~        细节就是实现类,实现接口或继承抽象类而产生的类就是细节
  4. 依赖倒置原则:
           ~~~~~~        i. 模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的;
           ~~~~~~        ii. 接口或抽象类不依赖于实现类;
           ~~~~~~        iii. 实现类依赖接口或抽象类。
  5. IOC控制反转:
    i.
           ~~~~~~        对象的控制权进行转移,例如,转移交给了IoC容器,它就是一个创建工厂。
           ~~~~~~               ~~~~~~        1) 需要的对象可以通过配置文件创建
           ~~~~~~               ~~~~~~        2) 依赖关系发生变化:原先的依赖关系消失,因为它们都依赖IoC容器。通过IoC容器建立它们之间的关系
           ~~~~~~        依赖注入(DI):所谓依赖注入,就是由IoC容器在运行期间,动态地将某种依赖关系注入到对象之中
  6. 总结:
           ~~~~~~        i. 依赖倒置原则的本质就是通过抽象(接口或抽象类)使各个类或模块的实现彼此独立,不互相影响,实现模块间的松耦合
           ~~~~~~        ii. 依赖倒置的基本要求:
           ~~~~~~               ~~~~~~        1) 每个类尽量都有接口或抽象类,或者抽象类和接口两者都具备
           ~~~~~~               ~~~~~~        2) 接口和抽象类都是属于抽象的,有了抽象才可能依赖倒置
           ~~~~~~        iii. 变量类型尽量是接口或者是抽象类
           ~~~~~~        iv. 任何类都不应该从具体类派生。(不一定)
           ~~~~~~        v. 尽量不要覆写基类的方法
           ~~~~~~               ~~~~~~        1) 如果基类是一个抽象类,而且这个方法已经实现了,子类尽量不要覆写。类间依赖的是抽象,覆写了抽象方法,对依赖的稳定性会产生一定的影响。
           ~~~~~~       

三、单一职责原则(Simple Responsibility Principle, SRP)

  1. 遵循单一职责原的优点有:
           ~~~~~~        i. 可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多。
           ~~~~~~        ii. 提高类的可读性,提高系统的可维护性。
           ~~~~~~        iii. 变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。
           ~~~~~~        iv. 需要说明的一点是单一职责原则不只适用于面向对象编程思想,只要是模块化的程序设计,都适用单一职责原则。
  2. 缺点:
           ~~~~~~        最明显的是会增加编写代码的复杂度。当我们按照职责把对象分解成更小的粒度之后,实际上也增大了这些对象之间相互联系的难度。
           ~~~~~~       

四、接口隔离原则(Interface Segregation Principle)

  1. 定义:用多个专门的接口,而不使用单一的总接口,客户端不应该依赖它不需要的接口。
  2. 我们在设计接口时应当注意以下几点:
           ~~~~~~        i. 一个类对一类的依赖应该建立在最小的接口之上。
           ~~~~~~        ii. 建立单一接口,不要建立庞大臃肿的接口。
           ~~~~~~        iii. 尽量细化接口,接口中的方法尽量少(不是越少越好,一定要适度)。
  3. 优点:
           ~~~~~~        接口隔离原则符合我们常说的高内聚、低耦合的设计思想,从而使得类具有很好的可读性、可扩展性和可维护性。在设计接口的时候,要多花时间去思考,要考虑业务模型,包括以后有可能发生变更的地方还要做一些预判。
           ~~~~~~       

五、迪米特法则(Law of Demeter, LoD)

  1. 定义:一个对象应该对其他对象保持最少的了解,又叫最少知道原则(Least Knowledge Principle, LKP),尽量降低类与类之间的耦合。
  2. 迪米特原则:主要强调只和朋友交流,不和陌生人说话。出现在成员变量、方法的输入、输出参数中的类都可以称之为成员朋友类,而出现在方法体内部的类不属于朋友类。
  3. 优点:
           ~~~~~~        i. 降低了类之间的耦合度,提高了模块的相对独立性。
           ~~~~~~        ii. 由于亲合度降低,从而提高了类的可复用率和系统的扩展性。
  4. 缺点:
           ~~~~~~        过度使用迪米特法则会使系统产生大量的中介类,从而增加系统的复杂性,使模块之间的通信效率降低。所以,在釆用迪米特法则时需要反复权衡,确保高内聚和低耦合的同时,保证系统的结构清晰。
           ~~~~~~       

六、里氏替换原则

  1. 定义:
           ~~~~~~        i. 如果对每一个类型为 T1 的 对象 o1,都有类型为 T2 的对象 o2,使得以 T1 定义的所有程序 P 在所有的对象 o1 都替换 成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。
           ~~~~~~        ii. 一个软件实体如果适用一个父类的话,那一定是适用于其子类,所有引用父类的地方必须能透明地使用其子类的对象,子类对象能够替换父类对象,而程序逻辑不变。
  2. 引申含义:子类可以扩展父类的功能,但不能改变父类原有的功能。
           ~~~~~~        i. 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
           ~~~~~~        ii. 子类中可以增加自己特有的方法。
           ~~~~~~        iii. 当子类的方法重载父类的方法时,方法的前置条件(即方法的输入/入参)要比父类 方法的输入参数更宽松。
           ~~~~~~        iv. 当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即 方法的输出/返回值)要比父类更严格或相等。
           ~~~~~~        好比开闭原则的案例时候在获取打折后时重写覆盖了父类的 getPrice()方法,增加了一个获取原价的方法 getOriginPrice(),显然就违背了里氏替换原则。我们修改一下代码,不应该覆盖 getPrice()方法,增加 getDiscountPrice ()方法。
           ~~~~~~       

七、合成复用原则(Composite Reuse Principle, CRP)

  1. 定义:
           ~~~~~~        i. 又叫组合/聚合复用原则。它要求在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。
           ~~~~~~        ii. 如果要使用继承关系,则必须严格遵循里氏替换原则。合成复用原则同里氏替换原则相辅相成的,两者都是开闭原则的具体实现规范。
  2. 复用分为继承复用和合成复用两种
           ~~~~~~        i. 继承复用虽然有简单和易实现的优点,但它也存在以下缺点:
           ~~~~~~               ~~~~~~        1) 继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为“白箱”复用。
           ~~~~~~               ~~~~~~        2) 子类与父类的耦合度高。父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展与维护。
           ~~~~~~               ~~~~~~        3) 它限制了复用的灵活性。从父类继承而来的实现是静态的,在编译时已经定义,所以在运行时不可能发生变化。
           ~~~~~~        ii. 组合或聚合复用:将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能,它有以下优点:
           ~~~~~~               ~~~~~~        1) 维持了类的封装性。因为成分对象的内部细节是新对象看不见的,所以这种复用又称为“黑箱”复用。
           ~~~~~~               ~~~~~~        2) 新旧类之间的耦合度低。这种复用所需的依赖较少,新对象存取成分对象的唯一方法是通过成分对象的接口。
           ~~~~~~               ~~~~~~        3) 复用的灵活性高。这种复用可以在运行时动态进行,新对象可以动态地引用与成分对象类型相同的对象。
  3. 合成复用原则的实现方法:
           ~~~~~~        合成复用原则是通过将已有的对象纳入新对象中,作为新对象的成员对象来实现的,新对象可以调用已有对象的功能,从而达到复用。
           ~~~~~~       

总结

在这里插入图片描述

七种设计原则:

开闭原则是总纲,它告诉我们要对扩展开放,对修改关闭;
里氏替换原则告诉我们不要破坏继承体系;
依赖倒置原则告诉我们要面向接口编程;
单一职责原则告诉我们实现类要职责单一;
接口隔离原则告诉我们在设计接口的时候要精简单一;
迪米特法则告诉我们要降低耦合度;
合成复用原则告诉我们要优先使用组合或者聚合关系复用,少用继承关系复用。

目的只有一个:降低对象之间的耦合,增加程序的可复用性、可扩展性和可维护性。

记忆口诀:访问加限制,函数要节俭,依赖不允许,动态加接口,父类要抽象,扩展不更改。

在程序设计时,我们应该将程序功能最小化,每个类只干一件事。若有类似功能基础之上添加新功能,则要合理使用继承。对于多方法的调用,要会运用接口,同时合理设置接口功能与数量。最后类与类之间做到低耦合高内聚。


网站公告

今日签到

点亮在社区的每一天
去签到