news 2026/6/26 17:40:42

深入理解面向对象设计原则:SOLID 原则

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深入理解面向对象设计原则:SOLID 原则


文章目录

  • 一、什么是 SOLID?
  • 二、S — 单一职责原则(SRP)
    • 定义
    • 解释
    • 反例(违反 SRP)
    • 正确做法(遵守 SRP)
  • 二、O — 开闭原则(OCP)
    • 定义
    • 解释
    • 反例
    • 正确做法(多态)
  • 三、L — 里氏替换原则(LSP)
    • 定义
    • 解释
    • 反例(经典正方形问题)
    • 正确设计(抽象)
  • 四、I — 接口隔离原则(ISP)
    • 定义
    • 解释
    • 反例
    • 正确做法(拆分接口)
  • 五、D — 依赖倒置原则(DIP)
    • 定义
    • 解释
    • 反例
    • 正确做法(面向接口)

一、什么是 SOLID?

SOLID是面向对象设计中最重要的一组原则,由 Robert C. Martin(Bob 大叔)由 2000 年在论文中提出,目标是:

让系统更易扩展、更易维护、更易理解、更少 Bug

而SOLID 缩略词是稍晚由 Michael Feathers 先使用的。Bob大叔的相关著作有《代码整洁之道》和《架构整洁之道》,也是大名鼎鼎。

SOLID 并不是语法规则,而是设计思想,在实际开发和面试中都极其重要。

SOLID 是 5 个设计原则首字母的缩写:

字母原则英文
S单一职责原则Single Responsibility Principle
O开闭原则Open–Closed Principle
L里氏替换原则Liskov Substitution Principle
I接口隔离原则Interface Segregation Principle
D依赖倒置原则Dependency Inversion Principle

它们共同目标:

降低耦合,提高内聚


二、S — 单一职责原则(SRP)

定义

一个类应该只有一个引起它变化的原因

解释

单一职责原则(Single Responsibility Principle)强调,一个类或模块应当只承担一种职责,并且只有一个引起它变化的原因。如果一个类同时负责多项功能,那么其中任意一项需求的变化都可能导致类被修改,从而增加系统的复杂度和出错风险。遵循单一职责原则可以让类的结构更加清晰,修改影响范围更可控,也更有利于代码的理解、测试和维护。

也就是说:
一个类只负责一件事


反例(违反 SRP)

classUserService{publicvoidregister(){// 注册逻辑}publicvoidsendEmail(){// 发送邮件}publicvoidwriteLog(){// 写日志}}

问题:

  • 注册
  • 邮件
  • 日志

👉 三种职责耦合在一个类中


正确做法(遵守 SRP)

classUserService{publicvoidregister(){System.out.println("用户注册");}}classEmailService{publicvoidsendEmail(){System.out.println("发送邮件");}}classLogService{publicvoidwriteLog(){System.out.println("写日志");}}

📌 好处:

  • 修改日志不影响注册逻辑
  • 类更清晰、更易维护

二、O — 开闭原则(OCP)

定义

对扩展开放,对修改关闭

解释

开闭原则(Open–Closed Principle)指出,软件实体应当对扩展开放、对修改关闭。也就是说,在新增功能时,应该通过扩展现有代码的方式来实现,而不是直接修改已经稳定运行的代码。这样可以有效降低引入新功能时对旧功能造成破坏的风险。开闭原则通常通过抽象、接口和多态来实现,是构建可扩展系统的核心设计思想之一。

新增功能时:

  • ✅ 扩展代码
  • ❌ 不修改原有代码

反例

classDiscountCalculator{publicdoublecalculate(Stringtype,doubleprice){if("VIP".equals(type)){returnprice*0.8;}elseif("NORMAL".equals(type)){returnprice*0.9;}returnprice;}}

问题:

  • 每加一种类型都要改if-else

正确做法(多态)

interfaceDiscount{doublecalculate(doubleprice);}classVipDiscountimplementsDiscount{publicdoublecalculate(doubleprice){returnprice*0.8;}}classNormalDiscountimplementsDiscount{publicdoublecalculate(doubleprice){returnprice*0.9;}}

📌 新增折扣类型只需新增类,不改旧代码


三、L — 里氏替换原则(LSP)

定义

子类必须能够替换父类,而不影响程序正确性

解释

里氏替换原则(Liskov Substitution Principle)是对继承关系的约束,它要求子类对象必须能够替换父类对象,而不会影响程序的正确性。如果在使用父类的地方替换成子类后,程序行为发生了改变或出现错误,那么这种继承关系本身就是不合理的。里氏替换原则提醒我们,继承不仅是代码复用,更是一种行为契约,子类应当遵守父类定义的语义。


反例(经典正方形问题)

classRectangle{protectedintwidth;protectedintheight;publicvoidsetWidth(intwidth){this.width=width;}publicvoidsetHeight(intheight){this.height=height;}publicintarea(){returnwidth*height;}}classSquareextendsRectangle{publicvoidsetWidth(intwidth){this.width=this.height=width;}publicvoidsetHeight(intheight){this.width=this.height=height;}}

使用时出错:

Rectangler=newSquare();r.setWidth(5);r.setHeight(10);System.out.println(r.area());// 100 ❌,期望 50

正确设计(抽象)

interfaceShape{intarea();}classRectangleimplementsShape{privateintwidth,height;publicRectangle(intw,inth){this.width=w;this.height=h;}publicintarea(){returnwidth*height;}}classSquareimplementsShape{privateintside;publicSquare(intside){this.side=side;}publicintarea(){returnside*side;}}

四、I — 接口隔离原则(ISP)

定义

客户端不应该被迫依赖它不使用的方法

解释

接口隔离原则(Interface Segregation Principle)强调,应当为不同的客户端提供专门的接口,而不是让所有实现类依赖一个臃肿的大接口。过于庞大的接口会迫使实现类实现它们并不需要的方法,从而导致不必要的依赖和冗余代码。通过将接口拆分为更小、更具体的接口,可以降低耦合度,提高系统的灵活性和可维护性。


反例

interfaceWorker{voidwork();voideat();}
classRobotimplementsWorker{publicvoidwork(){}publicvoideat(){}// ❌ 机器人不需要}

正确做法(拆分接口)

interfaceWorkable{voidwork();}interfaceEatable{voideat();}classHumanimplementsWorkable,Eatable{publicvoidwork(){}publicvoideat(){}}classRobotimplementsWorkable{publicvoidwork(){}}

五、D — 依赖倒置原则(DIP)

定义

高层模块不应该依赖低层模块,两者都应该依赖抽象

解释

依赖倒置原则(Dependency Inversion Principle)要求高层模块不应该依赖低层模块,两者都应该依赖抽象;抽象不应该依赖细节,细节应该依赖抽象。该原则的核心目的是减少模块之间的直接依赖,使系统更加稳定和易于扩展。通过引入接口或抽象类,高层业务逻辑可以在不关心底层实现细节的情况下进行开发,从而实现真正的解耦。


反例

classMysqlDatabase{publicvoidconnect(){System.out.println("连接 MySQL");}}classUserService{privateMysqlDatabasedb=newMysqlDatabase();}

问题:

  • UserService 强依赖 MySQL

正确做法(面向接口)

interfaceDatabase{voidconnect();}classMysqlDatabaseimplementsDatabase{publicvoidconnect(){System.out.println("连接 MySQL");}}classOracleDatabaseimplementsDatabase{publicvoidconnect(){System.out.println("连接 Oracle");}}
classUserService{privateDatabasedatabase;publicUserService(Databasedatabase){this.database=database;}}

相关参考

Java基础面试题-面向对象的设计原则你知道有哪些吗

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/26 10:27:14

VLA:AI如何革新视觉语言理解开发

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 使用快马平台构建一个基于VLA技术的图像描述生成应用。输入一张图片,AI自动生成详细的文字描述。要求支持多模态输入(图片文本),使用…

作者头像 李华
网站建设 2026/6/25 1:16:36

1Panel高效管理:多服务器批量操作实战指南

1Panel高效管理:多服务器批量操作实战指南 【免费下载链接】1Panel 项目地址: https://gitcode.com/GitHub_Trending/1p/1Panel 你是否曾经为管理多台服务器而感到力不从心?每次更新都要逐台登录、重复操作,不仅耗时耗力,…

作者头像 李华
网站建设 2026/6/23 15:53:12

WuWa-Mod模组终极指南:彻底改变《鸣潮》游戏体验

想要在《鸣潮》中体验前所未有的游戏乐趣吗?WuWa-Mod模组为你带来超过15种强大功能,从无限技能到智能拾取,让每一场冒险都充满惊喜。本文将为你提供完整的安装和使用方案。 【免费下载链接】wuwa-mod Wuthering Waves pak mods 项目地址: h…

作者头像 李华
网站建设 2026/6/23 23:34:47

发那科机器人CRM52A、CRM52B接口配置终极指南:快速上手与实战应用

发那科机器人CRM52A、CRM52B接口配置终极指南:快速上手与实战应用 【免费下载链接】发那科机器人CRM52ACRM52B接口说明 发那科机器人CRM52A、CRM52B接口说明 项目地址: https://gitcode.com/Open-source-documentation-tutorial/71d54 想要立即掌握发那科机器…

作者头像 李华
网站建设 2026/6/25 3:44:10

鸿蒙 Electron:跨端开发的极致融合,从原生能力调用到工程化部署

在跨端开发领域,Electron 凭借前端技术栈的低门槛和跨桌面平台的优势,成为桌面应用开发的主流选择;而鸿蒙(HarmonyOS)以 “分布式全场景” 为核心,构建了覆盖手机、平板、智慧屏、桌面设备的生态体系。将两…

作者头像 李华
网站建设 2026/6/26 2:48:44

WebClient在电商API集成中的实战应用

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 开发一个电商API集成工具,使用WebClient技术实现:1. 连接淘宝、京东、拼多多等主流电商平台API 2. 统一处理商品数据格式 3. 自动同步库存和订单状态 4. 异常…

作者头像 李华