面向对象设计原则——SOLID五原则

本文详细介绍了面向对象编程的三大特征——封装、继承、多态,并深入探讨了UML中类之间的关系,如继承、关联、聚合、组合和依赖。接着,文章重点阐述了SOLID五原则:单一职责原则、开闭原则、里氏替换原则、接口分离原则和依赖倒置原则,以及如何应用这些原则来提升代码质量。

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

一、面相对象编程(OOP)

客观现实世界程序世界
抽象实例化
对象 —> 类类(class) —> 对象(object)

面向对象编程范式

面向对象范式步骤
面向对象分析what项目需求(变化)
面向对象设计how以期用最小的代价适应项目需求变化
面向对象编程(OOP)do编码实现

面向对象的三大特征是:封装、继承、多态
大体逻辑如下:
对于现实生活中任意一个领域:

  • 必然是一个分类体系 —> “继承” —> 派生类对象 —> 对象的创建和销毁

  • 必然存在个体多样性 —> “多态” —> 抽象类、虚函数

  • 对于外行人不必了解领域内的细节 —> “封装” —> 权限修饰符

既然涉及到对象,必然涉及到对象的存储和相关计算 —> 需要"数据结构 + 算法"


二、UML统一建模语言(类图、类之间的关系)

1. 继承(泛化 generalization)

~ 表达的是:A is B 的关系


2. 关联关系

~ 表达的是:A has B 的关系
【分为:单向的、双向的】
关系是固定的
【彼此并不负责对方的生命周期】
【一般使用指针或引用】


3. 聚合关系

表达的是:对象之间为整体和部分的关系

  • 【比较强的关联关系】
  • 【"整体"不负责"部分"对象的销毁】
  • 整体不存在了,部分仍可作为零件单独存在

4. 组合关系

表达的是:对象之间为整体和局部的关系【A has B】

  • 【更强的关联关系】
  • 【"整体"负责"部分"对象的销毁】
  • 整体不存在了,部分也不复存在

5. 依赖关系

表达的是:从语义上来说是 A use B 的关系(是偶然的、临时的,并非固定的)

  • 【要借助函数调用来完成:】
  • 【B作为A的成员函数参数】
  • 【B作为A的成员函数的局部变量】
  • 【A的成员函数调用B的静态方法】

~【A use B 是通过函数来表现,而 A has B 是通过数据成员来表现】


6. 各关系的比较

继承体现的是类之间的纵向关系,其余四种体现的是类之间的横向关系
耦合强弱:依赖 < 关联 < 聚合 < 组合
从语义上来看:

  • 继承(A is B)
  • 关联、聚合、组合(A has B)
  • 依赖(A use B)
  • 当组合与依赖结合时,可以替代继承

组合+依赖(基于对象) v.s. 继承(面向对象)


重点补充:—>【如何判断两个类之间是什么关系?】

可以使用排除法:
例如C++多线程编程中,条件变量和互斥锁之间的关系

  1. 继承(A is B):显然不是;
  2. 组合(整体and局部,并且整体要负责局部的生命周期):显然也不是,二者生命周期互不干扰;
  3. 聚合:显然也不是,不是整体和局部的关系
  4. 依赖还是关联?
    ①依赖关系(A use B):是临时的,偶然的(函数形参,局部变量,调用静态方法)
    ②关联关系(A has B):是固定的,A has B

使用条件变量,就必要要使用互斥锁,没有互斥锁不行,显然是固定的关系,而且是单向的 —> 从而确定是关联关系



三、面向对象设计法则(SOLID五原则)

总原则:高内聚、低耦合

SOLID的5原则:

  1. 单一职责原则(Single Responsibility Principle)
  2. 开闭原则(Open Closed Principle)
  3. 里氏替换原则(Liscov Substitution Principle)
  4. 接口分离原则(Interface SegregationPrinciple)
  5. 依赖倒置原则(Dependency Inversion Principle)

1、单一职责原则(Single Responsibility Principle)

即:一个类,只干一件事情(意思是,只完成一个功能,并不是说只有一个函数)
(当一个类包含的功能太多时,会带来不必要的麻烦:比如,本来只需要其中一个功能,但必须把整个类引入,导致其他许多不必要的功能也不得已被引入了))

【例如:】

【左侧类本身只是想完成计算面积的功能,这需要依赖于Rectangle类,而Rectangle类中又包含了draw()方法,即使本来完全不应该用到,也只好因此而引入GUI库】

【重构成如下设计:】


2、开闭原则(Open Closed Principle)

对扩展开放,对修改封闭
【核心思想是:面对抽象编程,而不面对具体编程】
【让类依赖于特定的抽象】

【例如:经典例子:Figure <— Rectangle、Triangle、Circle】


3、里氏替换原则(Liscov Substitution Principle)

核心思想是:派生类必须能够替换基类(即,基类中的某些功能,派生类不需要的话,就要对基类进行拆分)

【例如:鸵鸟不会飞,因此基类Bird中就不应该有fly()方法】


4、接口分离原则(Interface Segregation Principle)

【核心思想是:使用多个小的专门的接口,而不要使用一个大的总接口

【例如:同样是鸵鸟】

【重构成如下设计:】

【原先设计:对于鸵鸟而言,鸵鸟不会飞,就无法使用该接口,可见"肥接口"导致接口通用性下降】
【重构设计:鸵鸟不会飞,就使用IBird接口;针对会飞的鸟,可以在该接口的基础上,再扩展新的接口,加入fly()方法,会飞的鸟可以使用此接口】


5、依赖倒置原则(Dependency Inversion Principle)

【核心思想是:面对接口编程,依赖于抽象】
【高层模块不依赖于低层模块,而是二者都同时依赖于抽象;抽象不依赖于具体,具体依赖于抽象】

【例如:】


6、迪米特法则(Law Of Demeter,最少知道原则)

一个软件实体应该尽可能少的与其他实体发生相互作用,同样是为了解耦
【例如:需要托关系找人完成一件事,我没必要也尽量不要直接去找那个人(实际上不熟找了也未必有用),而是通过我的朋友(我的朋友跟这个人很熟),让我的朋友替我去找他,作为中间人】


7、组合/聚合复用原则(Composite/Aggregate Reuse Principle,即 CARP)

尽量使用聚合、组合来达到复用,而少用继承(即,一个类中有另一个类的对象)
【因为使用继承常常会破坏基类-派生类的开闭原则】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值