欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > 一文彻底搞懂,设计模式六大原则(建议收藏)

一文彻底搞懂,设计模式六大原则(建议收藏)

2024/10/25 9:37:17 来源:https://blog.csdn.net/li396864285/article/details/142108654  浏览:    关键词:一文彻底搞懂,设计模式六大原则(建议收藏)

目录

    前言

    1.单一职责原则(Single Responsibility Principle, SRP)

    2.里氏替换原则(Liskov Substitution Principle, LSP)

    3.依赖倒置原则(Dependency Inversion Principle, DIP)

    4.接口隔离原则(Interface Segregation Principle, ISP)

    5.迪米特法则(Law of Demeter, LoD)

    6.开闭原则(Open-Closed Principle, OCP)

前言

设计模式的六大原则(SOLID)‌是软件工程中的基本原则,它们指导我们如何设计和构建可维护、可扩展的软件系统。

这六大原则分别是:

  • Single Responsibility Principle:单一职责原则

  • Open Closed Principle:开闭原则

  • Liskov Substitution Principle:里氏替换原则

  • Law of Demeter:迪米特法则

  • Interface Segregation Principle:接口隔离原则

  • Dependence Inversion Principle:依赖倒置原则

       六个原则的首字母联合起来(两个 L 算做一个)就是 SOLID (solid,稳定的),其代表的含义就是这六个原则结合使用的好处:建立稳定、灵活、健壮的设计。

‌1.单一职责原则(Single Responsibility Principle, SRP)

  定义:一个类应该只有一个引起它变化的原因。

There should never be more than one reason for a class to change.

  这意味着一个类应该只负责一项功能或责任,如果类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或抑制该类完成其他职责的能力。

图片

  例如,一个Animal类应该只负责某个动物的行为,而不应该同时处理不同动物的行为,这可以通过将不同动物的行为分离到不同的类中来实现。比如:创建类DogAnimal.dink(),实现狗的喝水动作,创建类CatAnimal.dink() 实现猫的喝水动作。

  当然,单一职责原则,不仅适用于类的设计,还适用于接口和方法的设计。接口的设计,应当只负责某个主体的行为集合,方法则只负责具体的某一个行为。

好处:

          1)更有利于代码高内聚,低耦合,降低类的复杂度。

          2)可读性更高,每个类职责清晰。

          3)可维护性更高,出现bug或者业务变更,都可以快速锁定修改代码范围,提高工作效率,降低改动风险。

2.里氏替换原则(Liskov Substitution Principle, LSP)

  所有引用基类的地方必须能透明地使用其子类的对象

Functions that use use pointers or references to base classes must be able to use objects of derived classes without knowing it.

  子类必须能够替换其基类而不会引起程序行为的改变。这意味着在软件设计中,我们应优先使用对象组合而不是类继承,以避免破坏基类已有的功能。

  通俗一点解释:只要有父类出现的地方,都可以用子类来替代,反过来则不行,有子类出现的地方,不能用其父类替代。

  里氏替换原则对继承的约束规则:

          1)子类必须实现父类抽象方法,但不得重写(覆盖)父类的非抽象(已实现)方法。

          2)子类中可以增加自己特有的方法。

          3)当子类覆盖或实现父类的方法时,方法的前置条件(即方法入参)要比父类方法的输入参数类型更宽松。

          例如:父类方法fun(HashMap map)入参是HashMap,那子类同名方法fun(Map map)可以定义入参为Map,反之则不行。

          4)当子类的方法实现父类的抽象方法时,方法的后置条件(即方法返回值)要比父类返回值类型更严格。

          例如:父类方法fun(HashMap map)#Map返回值是Map,则子类方法fun(HashMap map)#HashMap可以定义为HashMap,反之则不行。

3.依赖倒置原则(Dependency Inversion Principle, DIP)

  1)上层模块不应该依赖底层模块,它们都应该依赖于抽象。

  2)抽象不应该依赖于细节,细节应该依赖于抽象。

High level modules should not depend upon low level modules. Both should depend upon abstractions.

Abstractions should not depend upon details. Details should depend upon abstractions.

  高层模块不应该依赖于低层模块,两者都应该依赖于抽象。这意味着我们应该通过抽象层(如接口或抽象类)来定义模块间的依赖关系,而不是直接依赖具体的实现类。

图片

  依赖倒置本质上就是面向接口编程,它阐述两个事实:

  • 相对于细节的多变性,抽象的东西要稳定得多

  • 以抽象搭建起来的架构,比以细节搭建起来的要稳定得多

  例如:小明要从天津出差去北京,假如没有抽象的话,小明只能选择一种方式,乘坐汽车,那伪代码编程如下:

  Pepole xiaom = new Pepole();Car car = new Car();car.transport(xiaom, "天津", "北京");

  如果这时候,领导说,”汽车太慢了,小明你坐高铁去吧“,那我们的代码是不是就要改成:

  Pepole xiaom = new Pepole();HighSpeedRailway railway = new HighSpeedRailway();railway.transport(xiaom, "天津", "北京");

  如果只是这个地方需要改动,那还好,假如是该公司以后所有出行,都改成高铁出行,那岂不是所有地方都要改。

  如果我们采用抽象,抽象一个交通工具接口Transportation,再编写一个交通工具工厂类TransportationFactory,所有交通工具都实现Transportation,至于公司员工出差,选择什么交通工具,由工厂类根据实际需要去决定。

  改写后伪代码如下:

  Pepole xiaom = new Pepole();Transportation railway = TransportationFactory.get();railway.transport(xiaom, "天津", "北京");

     这时候,我们就再也不担心领导变来变去了,甚至我们可以这样决策,距离大于1000公里,选择飞机,1000公里以内选择高铁,100公里选择自驾,50公里选择公交。这就是面向接口的好处。

4.接口隔离原则(Interface Segregation Principle, ISP)

        1)客户端不应该依赖它不需要的接口。

        2)类间的依赖关系应该建立在最小的接口上。

Clients should not be forced to depend upon interfaces that they don`t use.

The dependency of one class to another one should depend on the smallest possible.

注:该原则中的接口,是一个泛泛而言的接口,不仅仅指Java中的接口,还包括其中的抽象类。

       为各个类创建小的专门的接口,而不是使用大的全面的接口。这样可以减少客户端代码对不需要的方法的依赖,提高系统的可维护性和可扩展性。

举例说明:回到上面小明出差的例子:汽车、轮船、高铁、飞机,都属于是交通工具,都有运输transport()的能力,是Transportation接口的,但是汽车、飞机、高铁都有轮子,轮船没有轮子,所以这时候我们还可以再抽象一个轮子接口Wheel.

对于汽车来说:

public class Car implements Transportation,Wheel{// 运输,方法来自于Transportationtransport(Pepole p, String sourceCity, String targetCity){……}// 轮子品牌,方法来自于WheelwheelBrand(……)// 轮子尺寸,方法来自于WheelwheelSize(……)
}

对于轮船来说,它没有轮子,就不用去实现Wheel接口。

这里需要注意的是,接口隔离原则和单一职责原则的区别如下:

        1)单一职责原则注重的是职责,而接口隔离原则注重的是对接口依赖的隔离。

        2)单一职责原则主要是约束类,它针对的是程序中的实现和细节;接口隔离原则主要约束接口,主要针对抽象和程序整体框架的构建。

5.迪米特法则(Law of Demeter, LoD)

只与你的直接朋友交谈,不跟“陌生人”说话

Talk only to your immediate friends and not to strangers

       也称为最少知识原则(Least Knowledge Principle),一个对象应当尽可能少地了解其他对象,以减少对象之间的耦合。这有助于降低类的复杂性,提高模块的独立性和可读性。

  • 从依赖者的角度来说,只依赖应该依赖的对象。

  • 从被依赖者的角度说,只暴露应该暴露的方法。

  • 应用场景‌:迪米特法则鼓励通过中介类或方法传递消息,避免直接的类间调用,从而减少系统的复杂度。

  • 优点‌:

    • 降低耦合度‌:通过减少对象之间的依赖关系,提升系统的灵活性和可维护性。

    • 提高模块化‌:有助于将功能模块化,便于进行单元测试和重构。

    • 增强代码可读性‌:清晰的责任边界使得代码更易于理解。

  • 缺点‌:过度使用迪米特法则可能会在系统中产生大量的中介类,增加系统的复杂度,降低不同模块之间的通信效率。

       迪米特法则与接口隔离原则在软件设计中有着密切的关系。接口隔离原则强调定义精简的接口,只暴露必要的方法给其他模块使用,这与迪米特法则中减少对象之间依赖的思想相辅相成。通过遵循接口隔离原则,可以进一步减少不必要的依赖,使得系统更加清晰和灵活。

6.开闭原则(Open-Closed Principle, OCP)

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

Software entities like classes, modules and functions should be open for extension but closed for modification

       软件实体(类、模块等)应当对扩展开放,对修改关闭。这意味着我们应当在不影响已有功能的前提下添加新功能,而不是修改现有的代码结构。

  • 开放‌:指的是软件实体应该能够接受新的功能或特性的扩展,而不需要修改现有的代码。

  • 关闭‌:指的是软件实体一旦完成,其内部实现细节应该保持稳定,不再允许被随意修改,除非是为了修正错误。

  • 重要性

    • 提高可维护性‌:减少因修改现有代码而引入新错误的风险。

    • 增强灵活性‌:通过扩展而非修改来添加新功能,使系统更加灵活。

    • 促进复用‌:设计良好的、遵循开闭原则的组件更易于被复用。

  • 实现方式

    • 抽象化‌:通过定义抽象类或接口来指定软件实体的行为,让子类或实现类具体实现这些行为。

    • 策略模式‌:使用策略模式可以根据需要动态地改变对象的行为,而无需修改对象本身。

    • 依赖注入‌:通过依赖注入技术,可以在不修改代码的情况下替换组件的依赖项,从而实现扩展。

       例如:我们继续以小明出差为例,假如出差工具需要多增加一种,比如公司公交专线,那么就有汽车、高铁、飞机、轮船、公交专线这几种交通工具了。

       此时我们直接新创建SpecialBus 继承 Transportation 就可以了,并不需要修改Car、Air这些类。

        如果觉得本文对您有帮助,麻烦帮忙点个关注~拜托啦!

图片

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com