Spring设计模式 八股速记 高层模块底层模块 依赖倒置原则 开闭原则 接口隔离原则

目录

高层模块底层模块

一、定义与核心思想

二、实现方式

三、优点与价值

四、典型应用场景

五、与其他原则的关系

示例说明

依赖倒置原则

一、定义与核心思想

二、实现方式

三、优点与价值

四、典型应用场景

五、与其他原则的关系

示例说明

自己理解

开闭原则

[1. 抽象化与接口设计](#1. 抽象化与接口设计)

[2. 封装与模块化](#2. 封装与模块化)

[3. 多态性与继承机制](#3. 多态性与继承机制)

[4. 依赖抽象而非具体实现](#4. 依赖抽象而非具体实现)

[5. 设计原则的协同作用](#5. 设计原则的协同作用)

总结

接口隔离原则

一、核心定义

二、与单一职责原则的区别

三、应用场景与实现方式

四、优缺点分析

五、注意事项

六、经典案例


高层模块底层模块


一、定义与核心思想
  1. 基本定义
    • 高层模块不应依赖低层模块,两者都应依赖抽象(接口或抽象类)。
    • 抽象不应依赖细节,而细节(具体实现类)应依赖抽象。
  1. 核心目标
    通过面向接口编程,打破传统"高层调用低层"的依赖关系,实现模块间解耦。例如:
    • 传统依赖:司机类直接调用奔驰车类的方法,导致更换车型需修改司机代码。
    • 倒置后:司机依赖"车辆接口",奔驰车、宝马车均实现该接口,实现灵活扩展。

二、实现方式
  1. 定义抽象层
    通过接口或抽象类规范模块间的交互契约。例如:
    • 定义消息发送接口 MessageService,由 EmailServiceSmsService 实现具体逻辑。
  1. 依赖注入(Dependency Injection)
    将具体实现通过构造函数、属性或方法参数注入到高层模块,而非在内部直接实例化。例如:

    public class NotificationService {
    private final MessageService messageService;
    // 通过构造函数注入依赖
    public NotificationService(MessageService messageService) {
    this.messageService = messageService;
    }
    }

  2. 避免直接引用具体类
    高层模块仅通过抽象接口操作,如顾客购物场景中依赖抽象的 Shop 接口,而非具体网店类。


三、优点与价值
  1. 降低耦合度
    模块间通过抽象交互,减少直接依赖,修改低层实现时无需调整高层代码。
  2. 提高可扩展性
    新增功能只需实现抽象接口,例如添加新车型或消息发送方式时,无需修改现有业务逻辑。
  3. 增强可测试性
    通过模拟抽象接口的实现,便于单元测试(如使用Mock对象)。
  4. 支持并行开发
    抽象接口定义后,高层与低层模块可独立开发。

四、典型应用场景
  1. 模块化系统设计
    在分层架构中,业务逻辑层(高层)通过接口调用数据访问层(低层),避免数据库变更影响业务代码。
  2. 框架开发
    如Spring框架通过依赖注入容器管理对象生命周期,实现组件解耦。
  3. 插件化扩展
    系统通过抽象接口支持第三方插件,如IDE工具可通过接口集成不同编译器。

五、与其他原则的关系
  • 开闭原则(OCP)的基础:依赖倒置通过抽象隔离变化,使系统易于扩展。
  • 里氏替换原则(LSP)的延伸:抽象接口的稳定性确保子类可替换性。

示例说明

场景:顾客在不同网店购物

  • 未遵循DIP:顾客类直接依赖韶关网店类,更换网店需修改顾客代码。

  • 遵循DIP后 :顾客依赖抽象的 Shop 接口,新增婺源网店只需实现该接口,无需修改顾客类。

    // 抽象接口
    public interface Shop {
    String sell();
    }
    // 具体实现
    public class WuyuanShop implements Shop {
    public String sell() { return "绿茶"; }
    }
    // 高层模块
    public class Customer {
    public void shopping(Shop shop) {
    System.out.println(shop.sell());
    }
    }


通过依赖倒置原则,系统从"细节驱动设计"转向"抽象驱动设计",显著提升灵活性和可维护性。实际开发中需结合依赖注入框架(如Spring)和接口设计规范落地此原则。

依赖倒置原则

依赖倒置原则(Dependency Inversion Principle,DIP)是面向对象设计的五大SOLID原则之一,其核心思想是通过抽象解耦模块间的直接依赖关系,提高系统的灵活性和可维护性。以下是关键要点解析:


一、定义与核心思想
  1. 基本定义
    • 高层模块不应依赖低层模块,两者都应依赖抽象(接口或抽象类)。
    • 抽象不应依赖细节,而细节(具体实现类)应依赖抽象。
  1. 核心目标
    通过面向接口编程,打破传统"高层调用低层"的依赖关系,实现模块间解耦。例如:
    • 传统依赖:司机类直接调用奔驰车类的方法,导致更换车型需修改司机代码。
    • 倒置后:司机依赖"车辆接口",奔驰车、宝马车均实现该接口,实现灵活扩展。

二、实现方式
  1. 定义抽象层
    通过接口或抽象类规范模块间的交互契约。例如:
    • 定义消息发送接口 MessageService,由 EmailServiceSmsService 实现具体逻辑。
  1. 依赖注入(Dependency Injection)
    将具体实现通过构造函数、属性或方法参数注入到高层模块,而非在内部直接实例化。例如:

    public class NotificationService {
    private final MessageService messageService;
    // 通过构造函数注入依赖
    public NotificationService(MessageService messageService) {
    this.messageService = messageService;
    }
    }

  2. 避免直接引用具体类
    高层模块仅通过抽象接口操作,如顾客购物场景中依赖抽象的 Shop 接口,而非具体网店类。


三、优点与价值
  1. 降低耦合度
    模块间通过抽象交互,减少直接依赖,修改低层实现时无需调整高层代码。
  2. 提高可扩展性
    新增功能只需实现抽象接口,例如添加新车型或消息发送方式时,无需修改现有业务逻辑。
  3. 增强可测试性
    通过模拟抽象接口的实现,便于单元测试(如使用Mock对象)。
  4. 支持并行开发
    抽象接口定义后,高层与低层模块可独立开发。

四、典型应用场景
  1. 模块化系统设计
    在分层架构中,业务逻辑层(高层)通过接口调用数据访问层(低层),避免数据库变更影响业务代码。
  2. 框架开发
    如Spring框架通过依赖注入容器管理对象生命周期,实现组件解耦。
  3. 插件化扩展
    系统通过抽象接口支持第三方插件,如IDE工具可通过接口集成不同编译器。

五、与其他原则的关系
  • 开闭原则(OCP)的基础:依赖倒置通过抽象隔离变化,使系统易于扩展。
  • 里氏替换原则(LSP)的延伸:抽象接口的稳定性确保子类可替换性。

示例说明

场景:顾客在不同网店购物

  • 未遵循DIP:顾客类直接依赖韶关网店类,更换网店需修改顾客代码。

  • 遵循DIP后 :顾客依赖抽象的 Shop 接口,新增婺源网店只需实现该接口,无需修改顾客类。

    // 抽象接口
    public interface Shop {
    String sell();
    }
    // 具体实现
    public class WuyuanShop implements Shop {
    public String sell() { return "绿茶"; }
    }
    // 高层模块
    public class Customer {
    public void shopping(Shop shop) {
    System.out.println(shop.sell());
    }
    }


通过依赖倒置原则,系统从"细节驱动设计"转向"抽象驱动设计",显著提升灵活性和可维护性。实际开发中需结合依赖注入框架(如Spring)和接口设计规范落地此原则。

自己理解

在依赖倒置原则中 高层模块不是调用底层模块

而是高层模块和底层模块都实现接口

底层模块实现接口

高层模块调用接口里面的方法

开闭原则

开闭原则(Open-Closed Principle, OCP)的基础是通过抽象化和多态性实现系统的可扩展性 ,其核心思想是在不修改已有代码的前提下扩展功能。以下是其具体基础要素:

1. 抽象化与接口设计

开闭原则的关键在于定义稳定的抽象层。通过接口或抽象类对功能进行抽象,将可变部分与不变部分分离,确保扩展时仅需新增实现而非修改原有结构。例如:

  • 通过接口定义通用行为(如宠物管理系统的 Pet 接口),具体实现通过多态扩展新类型(猫、狗、鸟);
  • 使用抽象类(如 AbstractChart)统一管理不同图表类型,新增图表仅需继承抽象类。
2. 封装与模块化
  • 封装变化:将可能变化的部分独立封装(如价格计算逻辑),通过新增类或配置实现扩展,而非直接修改原有类。
  • 模块化设计:系统划分为高内聚、低耦合的模块,每个模块职责单一,减少修改影响范围。
3. 多态性与继承机制
  • 利用多态特性,通过子类化扩展功能。例如,新增 OffNovelBook 子类实现打折逻辑,而非修改原书籍类;
  • 结合策略模式、装饰器模式等设计模式,动态替换行为。
4. 依赖抽象而非具体实现
  • 高层模块依赖接口或抽象类,而非具体实现类。例如,计算器类依赖 ArithmeticOperation 接口,支持灵活扩展加减乘除运算;
  • 遵循依赖倒置原则(DIP),确保系统核心逻辑与细节解耦。
5. 设计原则的协同作用
  • 里氏替换原则(LSP):子类可替换父类,保障扩展的兼容性;
  • 单一职责原则(SRP):每个类仅承担单一职责,降低修改风险。
总结

开闭原则的底层逻辑是通过抽象构建稳定框架,利用多态和封装实现灵活扩展。其成功应用依赖于合理的抽象设计、模块化架构以及与其他设计原则(如SOLID原则)的协同。这种设计模式显著提升了系统的可维护性、复用性和应对需求变化的敏捷性。

接口隔离原则(Interface Segregation Principle,ISP)是面向对象设计的SOLID原则之一,其核心思想是通过拆分臃肿的接口,减少类之间的不必要依赖,从而提高系统的灵活性和可维护性。以下是具体解析:


接口隔离原则

一、核心定义
  1. 基本概念
    客户端(接口使用者)不应被迫依赖其不需要的接口方法。应将庞大接口拆分为多个小接口,每个接口专注于单一功能。
  2. 核心目标
    • 降低耦合:通过细化接口,减少类对无关方法的依赖。
    • 提高内聚:每个接口专注单一职责,避免冗余实现。

二、与单一职责原则的区别
  • 单一职责原则(SRP)
    关注类或接口的职责单一性,强调业务逻辑的划分。
  • 接口隔离原则(ISP)
    强调接口设计的最小化,要求方法尽可能少,避免客户端被迫实现无用方法。

示例

一个电商系统的用户操作接口若包含登录、支付、订单管理等多个方法,违反ISP。应拆分为LoginablePayableOrderManageable等独立接口,让不同模块按需实现。


三、应用场景与实现方式
  1. 典型场景
    • 系统需要支持多种客户端(如移动端、PC端)访问不同功能。
    • 接口方法存在冗余(如打印机同时支持打印、扫描、传真,但部分客户端仅需部分功能)。
  1. 实现方法
    • 拆分接口 :将大接口按功能拆分为多个小接口(如PrinterScannerFaxMachine)。
    • 组合继承:通过接口继承组合所需功能,避免实现冗余方法。

代码示例

复制代码
// 拆分前:臃肿接口 
interface AllInOnePrinter {
    void print();
    void scan();
    void fax();
}
 
// 拆分后:符合ISP 
interface Printer { void print(); }
interface Scanner { void scan(); }
interface FaxMachine { void fax(); }
 
class BasicPrinter implements Printer { /* 仅实现打印 */ }
class AdvancedPrinter implements Printer, Scanner { /* 实现打印和扫描 */ }

四、优缺点分析

|--------------|-------------------------|
| 优点 | 缺点 |
| 减少类间耦合,提高扩展性 | 接口数量可能过多,增加管理成本 |
| 避免客户端实现无用方法 | 需平衡拆分粒度,过度拆分导致复杂度上升 |
| 提升代码可读性和维护性 | 可能引入重复接口定义(需结合其他设计模式优化) |


五、注意事项
  1. 适度拆分:接口粒度需结合业务场景,避免"为拆而拆"。
  2. 高内聚设计:每个接口应具备独立功能,且方法之间高度相关。
  3. 结合其他原则:如通过依赖注入(DI)或适配器模式灵活组合接口。

六、经典案例
  1. 美女筛选系统
    原接口IPrettyGirl包含外貌、身材、气质方法。拆分为IGoodBodyGirl(外形)和IGreatTemperamentGirl(气质),不同模块按需依赖。
  2. 数据库操作接口
    将通用的增删改查拆分为CRUD接口和特定功能接口(如分页查询),避免实现类冗余。

通过合理应用接口隔离原则,可以有效优化系统设计,减少"接口污染",使代码更灵活、健壮。更多案例可参考。

相关推荐
老马啸西风3 分钟前
Neo4j GDS-09-neo4j GDS 库中路径搜索算法实现
网络·数据库·算法·云原生·中间件·neo4j·图数据库
Python私教7 分钟前
Java手写链表全攻略:从单链表到双向链表的底层实现艺术
java·python·链表
小麟有点小靈20 分钟前
VSCode写java时常用的快捷键
java·vscode·编辑器
XY.散人30 分钟前
初识Redis · list和hash类型
数据库·redis·哈希算法
Arbori_2621530 分钟前
Oracle WITH 子句(也称为 公共表表达式,Common Table Expression,CTE)
数据库·oracle
程序猿chen31 分钟前
JVM考古现场(十九):量子封神·用鸿蒙编译器重铸天道法则
java·jvm·git·后端·程序人生·java-ee·restful
qianmoQ32 分钟前
GitHub 趋势日报 (2025年04月13日)
github
xiongmaodaxia_z735 分钟前
python每日一练
开发语言·python·算法
Tapdata1 小时前
拒绝停服, 随时回退:Sybase 到 Postgresql 的无缝数据库双向迁移方案
数据库
Chandler241 小时前
Go:接口
开发语言·后端·golang