当前位置: 首页 > news >正文

Java设计模式之开闭原则介绍与说明

一、开闭原则的定义与核心思想

  1. 定义
    软件实体应对扩展开放(新增功能时无需修改原有代码),对修改关闭(避免直接改动已稳定的功能代码)。

  2. 核心目标

    • 提高灵活性与稳定性:通过抽象化设计,使系统在扩展新功能时不影响现有逻辑。
    • 降低维护成本:减少因修改旧代码引入的潜在风险。

二、实现开闭原则的关键方法

  1. 抽象化设计
    • 接口或抽象类:定义稳定的抽象层,将具体实现细节交由子类或实现类完成。例如:
      interface Shape { void draw(); }
      class Circle implements Shape { /* 具体实现 */ }
      class Rectangle implements Shape { /* 具体实现 */ }
      
      新增三角形只需添加Triangle类,无需修改调用方代码。
  2. 设计模式的应用
    • 策略模式:将算法封装为独立类,通过组合实现行为扩展。例如支付方式的扩展:
      interface PaymentMethod { void pay(); }
      class CreditCard implements PaymentMethod { /* 实现 */ }
      class Alipay implements PaymentMethod { /* 实现 */ }
      
    • 工厂模式:通过工厂类动态创建对象,隔离客户端与具体实现。例如:
      interface Factory { Product create(); }
      class ConcreteFactory implements Factory { /* 创建具体产品 */ }
      
  3. 依赖倒置原则(DIP)的配合
    • 高层模块依赖抽象而非具体实现,例如通过接口注入:
      class GraphicEditor {public void draw(Shape shape) { shape.draw(); } // 依赖抽象Shape
      }
      

三、违反开闭原则的典型场景

  1. 条件判断蔓延
    • 若通过if-elseswitch硬编码处理不同情况,新增需求时需修改原有逻辑。例如:
      void drawShape(Shape shape) {if (shape.type == 1) drawCircle();else if (shape.type == 2) drawRect();
      }
      
      改进方案:通过多态实现,每个子类自行实现draw()方法。
  2. 直接修改核心类
    • 如文章4中的GraphicEditor类因新增图形类型而修改drawShape()方法,破坏了代码稳定性。

四、开闭原则的实际应用案例

  1. 输入法皮肤扩展
    • 定义抽象皮肤类AbstractSkin,具体皮肤(如DefaultSkinCSDNSkin)继承实现。输入法类通过注入不同皮肤实现动态切换,无需修改原有代码。
  2. 图形面积计算
    • 定义接口ICalculateArea,通用计算类CalculateArea提供默认实现。需更高精度时,继承并重写方法(如CalculateAreaExt),避免修改父类。

五、开闭原则与其他设计原则的关系

  1. 里氏替换原则(LSP):确保子类可替换父类,为开闭原则提供继承扩展的基础。
  2. 单一职责原则(SRP):职责单一的类更易扩展,降低修改风险。
  3. 依赖倒置原则(DIP):通过抽象层隔离高层与底层模块,支持灵活扩展。

六、总结与实践建议

  • 优先抽象,延迟实现:在设计初期定义清晰的接口或抽象类,预留扩展点。
  • 组合优于继承:通过组合复用现有功能,避免因继承导致的耦合问题。
  • 测试驱动设计:遵循开闭原则的代码更易测试,仅需针对新功能编写测试用例。
    通过以上方法,开闭原则能够显著提升代码的可维护性、可扩展性,是构建高质量Java系统的核心指导原则之一。
http://www.lryc.cn/news/615803.html

相关文章:

  • 深入解析Go设计模式:命令模式实战
  • 分布微服务电商订单系统Rust编码开发[上]
  • Rust进阶-part6-宏
  • [激光原理与应用-224]:机械 - 机械设计与加工 - 常见的术语以及含义
  • 每日算法刷题Day60:8.10:leetcode 队列5道题,用时2h
  • 机器学习-增加样本、精确率与召回率
  • Modbus RTU转Profinet网关接在线循环Na离子实现PLC读取温度值
  • C# 中常用集合以及使用场景
  • 本地WSL部署接入 whisper + ollama qwen3:14b 总结字幕增加利用 Whisper 分段信息,全新 Prompt功能
  • Framework开发之Zygote进程2(基于开源的AOSP15)--init.rc在start zygote之后的事情(详细完整版逐行代码走读)
  • 《解锁 C++ 基础密码:输入输出、缺省参数,函数重载与引用的精髓》
  • 【Linux | 网络】数据链路层
  • 九、Linux Shell脚本:运算符与表达式
  • 开启单片机
  • 服务器硬件电路设计之 I2C 问答(三):I2C 总线上可以接多少个设备?如何保证数据的准确性?
  • 笔试——Day34
  • 亚麻云之全球加速器——CloudFront(CDN)服务入门
  • 【Docker实战】Spring Boot应用容器化
  • ShadowKV 机制深度解析:高吞吐长上下文 LLM 推理的 KV 缓存“影子”方案
  • Python爬虫-爬取政务网站的文档正文内容和附件数据
  • 【后端】Java 8 特性 `User::getId` 语法(方法引用)介绍
  • 【东枫科技】NTN-IOT 卫星互联网原型系统,高达1.6G大带宽
  • MPLS特性之PHP(Penultimate Hop Popping)
  • Android快速视频解码抽帧FFmpegMediaMetadataRetriever,Kotlin(2)
  • 【软考中级网络工程师】知识点之 DCC 深度剖析
  • 【21】OpenCV C++实战篇——OpenCV C++案例实战二十七《角度测量》
  • Perplexity 为特朗普 Truth Social 提供技术支持
  • 如何培养自己工程化的能力(python项目)
  • Pytorch深度学习框架实战教程12:Pytorch混合精度推理,性能加速147%的技术实现
  • 若依前后端分离版学习笔记(八)——事务简介与使用