程序开发中面向对象的设计原则

本文详细介绍了SOLID设计原则,包括单一职责原则、开闭原则、里氏替换原则、接口隔离原则和依赖反转原则,并探讨了其他设计原则如KISS、YAGNI、DRY和迪米特法则。这些原则对于提高代码的可读性、可维护性和可扩展性至关重要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

学习一些经典的设计原则,再去学习设计模式,会事半功倍,设计模式是设计原则的实践总结提炼。

设计原则看似简单,但是在实际应用中却不是很好实践。需要理解透彻。

学习时需要取思考和掌握设计原则的设计初衷,能解决哪些问题,有哪些应用场景

SOLID设计原则

S:单一职责原则(Single Responsibility Principle)

A class should have one and only one reason to change, meaning that a class should have only one job.

单一职责,设计原则中最重要最基础的原则之一

如何理解单一职责原则

一个类只负责完成一个职责或功能,不要设计大而全的类,要设计粒度小,功能单一的类。主要目的是实现代码高内聚,低耦合,提高代码的可读性,可维护性,复用性

如何判断类的职责是否足够单一

不同阶段,不同需求,不同场景,对于一个类的职责是否单一,可能会有不同的判定结果。

比如下面几种就有可能说明类的设计不够单一

  • 类中的代码行数,属性,函数过多
  • 类依赖其他类过多,或者依赖类的其他类过多
  • 私有方法过多
  • 比较难给类起一个合适的名字
  • 类中大量的方法都是集中在类中的某几个属性

是否越单一越好

不是,还要考虑类的内聚性,有时为了单纯追求职责单一,强行将类进行拆分,导致内聚性不足,可读性变差,反倒得不偿失。如果真要隔离,可以考虑实现接口的方式,使用接口隔离原则来进行隔离

O:开闭原则(Open Closed Principle)

Objects or entities should be open for extension but closed for modification.

对拓展开放,对修改关闭

开闭原则也是设计原则最基础的原则之一,大多数为了解决代码拓展性问题而总结出来的设计模式,都是以开闭原则为指导原则。

理解开闭原则

简单理解一下,当添加一个新功能时,最好是在已有代码基础上拓展代码(新增模块,类,方法等),而非修改已有代码(修改模块,类,方法等)。

但是需要认识到的是,当我们新增功能的时候,不可能任何模块,类,方法的代码都不修改,我们要做的就是让修改操作更集中,更上层。以最小的修改代价完成新功能的开发。

同样的代码改动,在粗粒度下,可能被认为是修改,在细粒度下,可能被认为是拓展,需要根据实际业务进行辨别。

如何做到“对拓展开放,对修改关闭”

  • 要时刻具备拓展意识,抽象意识,封装意识。
  • 在设计代码时,事先根据业务需求留好拓展点,以便在未来需求变更时,在不改变代码整体结构,做到最小改动的情况下,将新功能灵活的插入到拓展点上。

如何提高拓展性

  • 使用多态,依赖注入,基于接口而非实现编程。
  • 使用设计模式:装饰,策略,模板,责任链,状态。

优点

  • 减少了因新增功能而导致的对已有功能的影响,
  • 集中修改,方便理解

L:里氏替换原则(Liskov Substitution Principle)

Let q(x) be a property provable about objects of x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T.

子类可以替换程序中父类出现的任何地方,且保证原来程序的逻辑行为不变及正确性不被破坏

和多态的区别

  • 多态是面向对象编程的一大特性,是一种代码实现的思路
  • 里氏替换是一种设计原则,用来指导继承关系中子类该如何设计,子类的设计要保证再替换父类的时候,不改变原有程序的逻辑和不破坏原有程序的正确性
  • 简单理解就是,不要对父类已实现方法进行重写,子类只添加拓展方法。

违反里氏替换原则

  • 子类违背父类声明要实现的功能。
  • 子类违背父类对输入,输出,异常的预定
  • 子类违背父类注释中所罗列的任何特殊说明
  • 最简单的就是不要取重写父类方法

I:接口隔离原则(Interface Segregation Principle)

A client should never be forced to implement an interface that it doesn’t use, or clients shouldn’t be forced to depend on methods they do not use.

偏向接口层面的职责单一,交互时不暴露无用的方法接口

理解接口隔离的“接口”

这里的接口有三种不同的理解

  • 理解为一组接口的集合:如果部分接口只被部分调用者使用,我们就要把这部分接口隔离出来,单独给这部分调用者使用,而不是让调用者也能看到不会被用到的接口。
// 如果只想给外部系统暴露查询操作,则转化成UserService即可做到接口隔离
public UserServiceImpl implements UserService,RestrictedUserService{
}
// 这里UserService接口中定义常用查询方法
public interface UserService{}
// 这里受限用户几口定义一些删除,修改方法
public interface RestrictedUserService{}
  • 理解位单个API接口或函数:部分调用者只需要函数中的部分功能,那我们就把函数拆成更细粒度的多个函数。
  • 理解为OOP中的接口,接口的设计要尽量单一,不要让接口的实现者和调用者,依赖不需要的接口函数。
  • 要利用好接口可以多实现的特性

接口隔离与单一职责的区别

  • 单一职责针对的是模块,类,接口的设计,接口隔离更侧重于接口的设计。
  • 接口隔离提供了一种判断接口职责是否单一的标准,如果调用者只是用部分接口或接口的部分功能,那接口的设计就不够指责单一

D:依赖反转原则(Dependency Inversion Principle)

Entities must depend on abstractions, not on concretions. It states that the high-level module must not depend on the low-level module, but they should depend on abstractions.

也叫依赖倒置,高层模块不依赖低层模块,应该使用抽象关联,抽象不依赖具体实现,具体实现依赖抽象

简单来说,在调用链上,调用者属于高层,被调用者数与低层。在平时的业务代码中高层模块依赖低层模块没有任何问题。实际上,这条原则主要还是指导框架层面的设计。

比如tomcat容器和web应用之间没有直接的依赖关系,两者都依赖同一个抽象,也就是servlet规范。Servlet规范不依赖tomcat容器和应用程序的实现细节,反而是容器和应用程序依赖Servlet规范。

控制反转

控制值得是对程序程序执行流程的控制,而反转指的是没有使用框架之前,程序员自己控制整个程序的执行,使用框架后,整个程序的控制流程可以通过框架来控制。流程的控制权从程序员反转到了框架上。

模板方法模式就是个很好的例子,上层框架来出来执行流程,而自己只需要实现流程过程中的拓展点即可。

依赖注入

指不通过new的方式在类内部创建依赖类的对象,而是将对象在外部创建好后,通过构造函数,函数参数等方式传递(注入)给类来使用。

依赖注入框架

通过简单配置所有需要的类及其类与类之间的依赖关系,就可以实现由框架来自动创建对象,管理对象生命周期,依赖注入等原本需要程序员来做的事情。

其他常见设计原则

KISS原则(Keep It Simple, Stupid)

  • KISS原则是英语Keep It Simple, Stupid 的首字母缩略字,是一种归纳过的经验原则。KISS 原则是指在设计当中应当注重简约的原则。总结工程专业人员在设计过程中的经验,大多数系统的设计应保持简洁和单纯,而不掺入非必要的复杂性,这样的系统运作成效会取得最优;因此简单性应该是设计中的关键目标,尽量回避免不必要的复杂性。同时这原则亦有应用在商业书信、设计电脑软件、动画、工程上
  • KISS原则是保持代码可读和可维护的重要手段
  • 不要使用同事可能不懂的技术来实现代码;
  • 不要重复造轮子,要善于使用已经有的工具类库;
  • 不要过度优化。
  • KISS原则就是保持代码可读和可维护的重要手段。代码足够简单,也就意味着很容易读懂,bug比较难隐藏。即便出现bug,修复起来也比较简单。

YAGNI原则(You aren't gonna need it)

不要去设计当前用不到的功能;不要去编写当前用不到的代码。实际上,这条原则的核心思想就是:不要做过度设计。

当前不需要就不要做

DRY原则(Don’t Repeat Yourself)

不要写重复的代码。

常见的有:实现逻辑重复、功能语义重复和代码执行重复

提高代码复用性

  • 减少代码耦合
  • 满足单一职责原则
  • 模块化
  • 业务与非业务逻辑分离
  • 通用代码下沉
  • 继承、多态、抽象、封装
  • 应用模板等设计模式

迪米特法则(Law of Demeter)

最小知识原则

高内聚,低耦合

基于最小接口而非最大实现编程

每个模块(unit)只应该了解那些与它关系密切的模块(units: only units “closely” related to the current unit)的有限知识(knowledge)。或者说,每个模块只和自己的朋友“说话”(talk),不和陌生人“说话”(talk)。

不该有直接依赖关系的类之间,不要有依赖;

有依赖关系的类之间,尽量只依赖必要的接口

这里和接口隔离原则类似

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值