程序员必知!开放封闭原则的实战应用与案例分析

开放封闭原则是面向对象设计中的重要原则之一,它要求软件实体(类、模块、函数等)应该对扩展开放,但对修改关闭。这意味着当需要添加新功能时,不应该修改现有的代码,而是应该通过扩展来实现。这可以通过使用接口、抽象类和多态等机制来实现,从而使系统更加灵活和可扩展。

程序员必知!开放封闭原则的实战应用与案例分析 - 程序员古德

定义

开放封闭原则(Open Closed Principle,简称OCP)是面向开放封闭原则(Open Closed Principle,简称OCP)是面向对象设计中的一个重要原则,它由Bertrand Meyer于1988年提出。该原则主张软件实体(类、模块、函数等等)应该对扩展开放,对修改关闭,这意味着,当需要添加新功能时,我们应该尽量通过扩展已有的代码来实现,而不是修改原有的代码。

该原则的核心思想是,对于已经设计好的软件实体,应该在不修改其源代码的情况下,通过扩展来增加新的功能或行为。换句话说,我们应该尽可能地保持软件实体的稳定性和可靠性,而不是通过修改源代码来适应新的需求。在实现开放封闭原则时,需要注意以下几点:

  1. 对扩展开放:当需要添加新功能时,应该通过扩展现有的类或模块来实现,而不是修改现有的代码。这可以通过使用接口、抽象类和多态等机制来实现。
  2. 对修改关闭:当添加新功能时,不应该修改现有的代码。如果必须修改现有的代码,那么这种修改应该是有计划、有目的的,并且应该尽量避免对其他部分的代码产生影响。
  3. 抽象化设计:通过抽象化设计,可以将具体的实现细节隐藏在抽象接口之后,从而保护现有的代码不被修改。同时,抽象化设计也可以提高代码的可重用性和可维护性。
  4. 模块化设计:通过模块化设计,可以将系统划分为多个独立的模块,每个模块都有明确的职责和功能。这样可以降低系统的耦合度,提高系统的可维护性和可扩展性。

程序员必知!开放封闭原则的实战应用与案例分析 - 程序员古德

代码案例

假设我们正在开发一个电商系统,其中包括一个订单处理模块,该模块负责处理用户的订单,包括计算订单金额、生成订单号、发送订单确认邮件等功能。

首先,我们来看一个不符合开放封闭原则的设计,代码如下:


/*** @版权 Copyright by 程序员古德 <br>* @创建人 程序员古德 <br>* @创建时间 2023/12/15 16:37 <br>*/// 不符合开放封闭原则的设计  public class OrderProcessor {  public void processOrder(Order order) {  // 计算订单金额  double amount = calculateOrderAmount(order);  // 生成订单号  String orderNumber = generateOrderNumber();  // 发送订单确认邮件  sendOrderConfirmationEmail(order, amount, orderNumber);  // 其他订单处理逻辑...  }  private double calculateOrderAmount(Order order) {  // 计算订单金额的逻辑  return 0.0;  }  private String generateOrderNumber() {  // 生成订单号的逻辑  return null;  }  private void sendOrderConfirmationEmail(Order order, double amount, String orderNumber) {  // 发送订单确认邮件的逻辑  }  
}

在上面的代码中,OrderProcessor类负责处理订单的全部逻辑,包括计算金额、生成订单号、发送确认邮件等。如果我们需要添加新的功能,比如添加优惠券处理逻辑,就需要修改OrderProcessor类的代码,这样不符合开放封闭原则,每次添加新功能都需要修改已有代码,会增加系统的维护成本,并且容易引入错误。

为了解决这个问题,我们可以使用开放封闭原则进行改进,我们可以将订单处理的不同功能抽象为不同的接口,比如OrderAmountCalculatorOrderNumberGeneratorOrderConfirmationEmailSender等。然后,我们可以实现这些接口来提供具体的功能实现,这样,当需要添加新功能时,只需要扩展相应的接口,而不需要修改已有的代码,下面是改进后的代码:


/*** @版权 Copyright by 程序员古德 <br>* @创建人 程序员古德 <br>* @创建时间 2023/12/15 16:37 <br>*/// 符合开放封闭原则的设计  public interface OrderAmountCalculator {  double calculate(Order order);  
}  public interface OrderNumberGenerator {  String generate();  
}  public interface OrderConfirmationEmailSender {  void send(Order order, double amount, String orderNumber);  
}  public class SimpleOrderAmountCalculator implements OrderAmountCalculator {  @Override  public double calculate(Order order) {  // 计算订单金额的逻辑  return 0.0;  }  
}  public class SimpleOrderNumberGenerator implements OrderNumberGenerator {  @Override  public String generate() {  // 生成订单号的逻辑  return null;  }  
}  public class SimpleOrderConfirmationEmailSender implements OrderConfirmationEmailSender {  @Override  public void send(Order order, double amount, String orderNumber) {  // 发送订单确认邮件的逻辑  }  
}  public class OrderProcessor {  private OrderAmountCalculator orderAmountCalculator;  private OrderNumberGenerator orderNumberGenerator;  private OrderConfirmationEmailSender orderConfirmationEmailSender;  public OrderProcessor(OrderAmountCalculator orderAmountCalculator, OrderNumberGenerator orderNumberGenerator, OrderConfirmationEmailSender orderConfirmationEmailSender) {  this.orderAmountCalculator = orderAmountCalculator;  this.orderNumberGenerator = orderNumberGenerator;  this.orderConfirmationEmailSender = orderConfirmationEmailSender;  }  public void processOrder(Order order) {  double amount = orderAmountCalculator.calculate(order);  String orderNumber = orderNumberGenerator.generate();  orderConfirmationEmailSender.send(order, amount, orderNumber);  // 其他订单处理逻辑...  }  
}  

在上面的代码中,我们将订单处理的不同功能抽象为了不同的接口,并且提供了相应的实现类,这样,当需要添加新功能时,只需要扩展相应的接口,并提供一个新的实现类即可,比如,如果我们想要添加优惠券处理逻辑,可以创建一个实现了OrderAmountCalculator接口的CouponOrderAmountCalculator类,然后在创建OrderProcessor对象时传入这个新的实现类即可。这种方式符合开放封闭原则,可以在不修改已有代码的情况下扩展系统的功能。同时,由于使用了接口进行抽象,代码的可读性和可维护性也得到了提高,这种方式可以使我们的系统更加灵活和可扩展。

核心总结

程序员必知!开放封闭原则的实战应用与案例分析 - 程序员古德

开封封闭原则(Open-Closed Principle,OCP)是面向对象设计的五个基本原则之一,它指导我们设计模块时应尽量使其对扩展开放,对修改关闭,这意味着我们可以增加新的功能,而不需要改动已有的代码。

优点:一是提高软件的可维护性,因为修改原有代码可能会引入新的错误;二是有利于团队协作,每个人都可以在不干扰其他人的情况下添加新功能;三是有利于复用,因为每个类或模块只做一件事,所以更容易找到可以复用的代码。

缺点:一是过度设计,如果预设了过多的扩展点,可能导致代码过于复杂;二是可能增加系统的耦合度,因为为了满足开封封闭原则,可能需要引入一些抽象类或接口。

使用建议:在实际开发中,我们应该根据项目需求和规模来权衡是否严格遵循开封封闭原则。对于小型项目或者短期内不会频繁变动的项目,可能不需要过度设计。而对于大型项目或者需要长期维护的项目,遵守开封封闭原则则更为重要。同时,我们也应该注意避免过度设计和增加系统耦合度的问题,可以通过重构和优化代码结构来解决这些问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/288592.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【openwrt学习笔记】IPV6 ND协议学习和socket编程

目录 一、参考链接二、学习目标三、代码解析3.1 仅解析NA报文保存设备mac和ipv6地址信息3.1.1 open_ns_socket3.1.2 recv_ns_pack 3.2 解析NA和NS报文中DAD报文保存设备mac和ipv6地址信息3.2.1 open_ns_na_socket3.2.2 recv_ns_na_pack 四、代码优化4.1 BPF参考学习资料4.2 代码…

VCP-DCV VMware vSphere,12月23日即将开课~想了解点击查看

VCP-DCV VMware vSphere 本周开课~ 想报名的必须提前预约啦 &#x1f447;&#x1f447;&#x1f447; 课程介绍 本课程重点讲授如何安装、配置和管理VMware vSphere 8.0&#xff08;包括VMware ESXi™ 8.0和VMware vCenter Server™ 8.0&#xff09; 本课程将帮助您做好为任…

【项目管理】redmine

Redmine是用Ruby开发的基于web的项目管理软件&#xff0c;是用ROR框架开发的一套跨平台项目管理系统&#xff0c;据说是源于Basecamp的ror版而来&#xff0c;支持多种数据库&#xff0c;有不少自己独特的功能&#xff0c;例如提供wiki、新闻台等&#xff0c;还可以集成其他版本…

故障排查:shell脚本输出乱码

博客主页&#xff1a;https://tomcat.blog.csdn.net 博主昵称&#xff1a;农民工老王 主要领域&#xff1a;Java、Linux、K8S 期待大家的关注&#x1f496;点赞&#x1f44d;收藏⭐留言&#x1f4ac; 目录 故障详情故障原因解决方法iconv命令介绍 故障详情 最近的工作中遇到一…

【每日一题】【12.20】2828.判别首字母缩略词

&#x1f525;博客主页&#xff1a; A_SHOWY&#x1f3a5;系列专栏&#xff1a;力扣刷题总结录 数据结构 云计算 数字图像处理 力扣每日一题_ 1.题目链接 2828. 判别首字母缩略词https://leetcode.cn/problems/check-if-a-string-is-an-acronym-of-words/ 2.题目描述 今天…

【动态规划】08路径问题_下降路径最小和_C++(medium)

题目链接&#xff1a;leetcode下降路径最小和 目录 题目解析&#xff1a; 算法原理 1.状态表示 2.状态转移方程 3.初始化 4.填表顺序 5.返回值 编写代码 题目解析&#xff1a; 题目让我们求通过 matrix 的下降路径 的 最小和 由题可得&#xff1a; 在下一行选择的元…

Python 操作mysql实现事务处理

一、应用场景 Python项目对MySQL数据库进行增、删、改操作时&#xff0c;有时会出现执行sql异常的情况。在批量提交数据的时候&#xff0c;如果其中一个事务提交错误&#xff0c;往往导致预期的整个数据链不完整。 例如银行转账数据&#xff0c;用户A向用户B转账&#xff1a; …

Navicat16的下载与安装

Navicat16的下载与安装 1、官网下载地址&#xff1a;https://www.navicat.com.cn/download/navicat-premium 当然有的朋友在官网下载比较慢&#xff0c;我也为大家准备好了百度网盘链接 链接&#xff1a;https://pan.baidu.com/s/1dUcTSHr3761Oayh0-WfolA?pwdwfpl 提取码&am…

【Java】常用的时间类API

目录 Date(时间和日期) SimpleDateFormat&#xff08;解析字符串时间成为时间对象&#xff09; Calendar(系统此刻时间对应的日历) LocalDate&#xff08;年、月、日&#xff09; LocalTime&#xff08;时、分、秒&#xff09; LocalDateTime&#xff08;年、月、日、时、分、秒…

LeetCode 每日一题 Day 17 || 二分

1901. 寻找峰值 II 一个 2D 网格中的 峰值 是指那些 严格大于 其相邻格子(上、下、左、右)的元素。 给你一个 从 0 开始编号 的 m x n 矩阵 mat &#xff0c;其中任意两个相邻格子的值都 不相同 。找出 任意一个 峰值 mat[i][j] 并 返回其位置 [i,j] 。 你可以假设整个矩阵周…

vue 如何实现拖动:vue-draggable

vue-draggable 官方文档&#xff1a;传送门 特点&#xff1a; 支持触摸设备&#xff08;如vue项目的移动端开发Quasar&#xff09;支持拖拽和选择文本支持不同列表之间的拖拽视图模型的同步刷新与vue2的过渡动画&#xff08;transition-group&#xff09;兼容有很多监听函数…

Python MySQL数据库连接实现增删改查

一、应用场景 python项目连接MySQL数据库时&#xff0c;需要第三方库的支持。这篇文章使用的是PyMySQL库&#xff0c;适用于python3.x。 二、安装 pip install PyMySQL三、使用方法 1.导入模块 import pymysql2.连接数据库 db pymysql.connect(hostlocalhost,usercode_s…