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

【设计模式】软件设计原则——开闭原则里氏替换单一职责

开闭原则内容引出

 

开闭原则

定义:一个软件实体,类,函数,模块;对扩展开放,对修改关闭。用抽象构建框架,用实现扩展细节。可以提高软件的可复用性和可维护性。

开发新功能时,尽量不修改原有代码,尽量使用扩展来增加新功能。

实现开闭原则的核心思想是:面向抽象编程,而不是面向实现编程。

定义的对象类型是:抽象or接口;调用的是抽象类or接口中的方法。抽象是稳定的,让一个类依赖于抽象,实现对修改关闭。再通过面向对象的继承多态,实现对抽象的继承,通过重写方法or实现新的扩展方法。

开闭原则示例

/*** 商品接口*/
public interface IGood {Integer getId();String getName();Double getPrice();
}
/*** 普通商品*/
public class NormalGood implements IGood {private Integer id;private String name;private Double price;public NormalGood(Integer id, String name, Double price) {this.id = id;this.name = name;this.price = price;}@Overridepublic Integer getId() {return this.id;}@Overridepublic String getName() {return this.name;}@Overridepublic Double getPrice() {return this.price;}@Overridepublic String toString() {return "...普通商品信息"}
}
/**
添加打折功能
根据开闭原则 , 对修改关闭 , 对扩展开放;
定义子类,在继承普通商品的基础上,扩展的新功能;
不用实现接口,而是继承普通类。
站在会员卡角度如下:
card接口;普通用户类;银卡继承普通用户;金卡继承银卡
*/
public class DiscountGood extends NormalGood {public DiscountGood(Integer id, String name, Double price) {super(id, name, price);}@Overridepublic Double getPrice() {return super.getPrice() * 0.8;//折扣位置}
}

里氏替换原则

子类可以扩展父类的功能,但不能改变父类原有的功能。

是开闭原则的重要方式之一,由于使用父类对象的地方都可以使用子类对象,因此在程序中尽量使用父类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。

public class FatherClass {public void method(HashMap map) {System.out.println("执行父类 void method(HashMap map) 方法");}
}public class ChildClass extends FatherClass {/*** 重写* 重写 ( 返回值 严格 ) : 当 子类的方法 重写 / 重载 / 实现 父类的方法时*      方法的 后置条件 ( 返回值 ) 要 比父类更严格或相等;*/@Overridepublic void method(HashMap map) {System.out.println("执行子类重写的 void method(HashMap map) 方法");}/*** 重载* 重载 ( 输入参数 宽松 ) : 子类的方法 重载 父类的方法 时*      方法的前置条件 ( 输入参数 ) , 要比 父类方法的输入参数更宽松 ;** 如果在父类中参数类型是 Map*      在子类中重载参数类型是 HashMap*      这样就会出现混乱的问题* 客户端调用时 , 可能不清楚情况 , 加入传入了 HashMap 参数*      此时就有可能出现混乱 , 无法调用到 父类/子类的 正常重写方法*      方法调用被重载方法拦截的情况** 如果 重载的方法 的参数 比父类的方法参数更严格*      那么这就不是重载方法 , 而是重写方法*/public void method(Map map) {System.out.println("执行子类重载的 void method(Map map) 方法");}}

 


 单一职责内容引出

单一职责

定义:不要存在多余一个导致类变更的原因。

假设有一个类,负责“A”和“B”;一旦需求变更,如A功能改变,修改该类A功能时,有可能导致B功能发生故障。对于该情况,应该对于AB各自建立独立的类,保证系统的稳定性。

开发方法:一个类只负责一项职责(类、接口、方法)

优点:可读性高、提高系统可维护性、降低类的复杂度、降低需求变更导致的风险。

模块化的系统中,都适合使用单一职责。

//以下代码均违反了单一职责原则
public class Dog{public void mainDogs(String name) {if ("小狗".equals(name)) {System.out.println("puppy's name is "+name);} else {System.out.println("Dog's name is "+name);}}
}//-----------------------------------------------------------------public class Order {private String orderId;private String userId;private String productId;private double amount;private OrderStatus status;public void createOrder(String userId, String productId, double amount) {// 创建订单  }public void payOrder() {// 支付订单  }public void shipOrder() {// 发货 }public void completeOrder() {// 完成订单 }
}

类的单一

/***本类的职责单一,只负责puppy*/
public class Puppy{public void IsPuppy(String name) {System.out.println("Puppy's name is "+name);}
}
public class Dog{public void IsDog(String name) {System.out.println("Dogs's name is "+name);}
}//--------------------------------------------------
// 订单接口
public interface Order {void create();void pay();void ship();void complete();
}// 创建类
public class OrderCreator implements Order {@Overridepublic void create() {// 创建订单的业务逻辑}
}...其他业务类// 订单完成类
public class OrderCompleter implements Order {@Overridepublic void complete() {
// 完成订单的逻辑}
}

方法单一

如果方法中存在大片的if-else说明是不完善的代码,而我们在开发中其实应该避免如is-else或者switch等条件语句。

//违反单一原则的代码
//如果只针对价格or名字or描述进行修改,会连带修改另外两个,存在一定风险
public class Good {public void updateGoodInfo(String name, double price,String description) {//更新商品信息逻辑}
}//修改后:
public class Good{public void updateGoodName(String Name){//修改名字}public void updateGoodPrice(String Name){//修改价格}public void updateGoodDescription(String Name){//修改商品描述}}

接口单一

public interface IGood {//获取名称String getName();//获取价格double getPrice();//获取商品描述String getDescription();//购买void buyGood();
}//-----------------------拆分------------------------
public interface IGoodInfo{//接口1,商品信息接口String getName();String getDescription();double getPrice();
}public interface IGoodManage{void buyGood();//接口2,商品操作接口//退换等其他逻辑
}//商品实现
publci class IGoodImpl implements IGoodInfo,IGoodManage{@Override//.....
}

相关文章:

【设计模式】软件设计原则——开闭原则里氏替换单一职责

开闭原则内容引出 开闭原则 定义:一个软件实体,类,函数,模块;对扩展开放,对修改关闭。用抽象构建框架,用实现扩展细节。可以提高软件的可复用性和可维护性。 开发新功能时,尽量不修…...

项目完整开发的流程

流程 1.设计产品 2.写需求文档 2.1需求分析,后端设计数据库,建表,客户沟通,说完签字,留证据,防止后面扯皮,和防止后续变需求重新写业务 3.画原型图,也就是草图,初始的…...

性能测试学习6:jmeter安装与基本配置/元件/线程组介绍

一.JDK安装 官网:https://www.oracle.com/ 二.Jmeter安装 官网:http://jmeter.apache.org/download_jmeter.cgi 下载zip包,zip后缀那个才是Windows系统的jmeter 三.Jmeter工作目录介绍 四.Jmeter功能 1)修改默认配置-汉化 2&am…...

大数据ETL数据提取转换和加载处理

什么是 ETL? 提取转换加载(英语:Extract, transform, load,简称ETL),用来描述将资料从来源端经过抽取、转置、加载至目的端的过程。ETL一词较常用在数据仓库,但其对象并不限于数据仓库。 ETL&…...

物理与环境安全技术

目录 物理安全 环境安全 物理安全 物理安全是指通过实施一系列的防护措施,以保护人员、设备、设施和信息资源免受物理上的威胁、损坏或非法入侵。 访问控制:限制对数据中心、机房等关键设施的物理访问。通常采用的措施有门禁系统(使用门禁…...

手把手教你如何配置好VS Code的WEB基础开发环境(保姆级)

1. VS Code介绍 微软旗下的多场景开发环境软件,支持JAVA、C、C#、C、WEB、VUE、CSS、HTML、Python等等等 如果你刚刚开始编程或者准备学习WEB,那么我强烈建议你使用这款软件 缺点:(针对初学者) 需要安装各种各样的插…...

高性能、编译器编写语言、编程语言的高低贵贱

高性能 高性能是一个通用名词,可在服务器、客户端甚至浏览器实现高性能。对于大型网站、服务器后端、游戏后端,高性能是一个不可绕过的槛。 高性能技术 池机制 静态分配:就像编译型语言对代码的预处理,不像解释型语言动态解析。可…...

Python安装库时使用国内源pip install -i

普通 安装方式会从国外站点下载, 首先是慢,再有可能会下载失败 所以一般指定国内源 示例 正常情况下,安装pandas这个模块 pip install pandas指定源命令如下: pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ pan…...

Linux 再入门整理:详解 /etc/fstab 文件

目录 1. 什么是 /etc/fstab2. /etc/fstab 文件的格式2.1 设备文件 (Device)2.2 挂载点 (Mount Point)2.3 文件系统类型 (File System Type)2.4 挂载选项 (Mount Options)2.5 Backup Operation(dump 参数)2.6 Pass Order (fsck 参数)2.6.1 参数设置2.6.2 …...

2.8 双绞线、同轴电缆、光纤与无线传输介质

传输介质及分类 传输介质也称为传输媒体,它是发送设备和接收设备之间的物理通路。 传输介质可分为导向传输介质和非导向传输介质。在导向传输介质中,电磁波被导向沿着固体媒介(铜线或光纤)传播,而非导向传输介质可以…...

OBOO鸥柏:布局于为无人机展厅行产业提供LCD液晶显示终端

新华网快讯,于10月9日消息,有投资者在互动平台向OBOO鸥柏公司提问:您好!目前有哪些工业/商用显示产品应用于无人机展厅展馆场景?能否着重介绍下贵司屏幕主要应用哪些品牌无人机数字化展厅展馆做保障? 鸥柏…...

win10状态栏中 “音量” 符号丢失,而在“打开或关闭系统图标”中音量开关无法调节的解决方法

最近在使用电脑需要调节音量时,突然发现电脑右下角的音量图标不见了,在网上搜索了,测试了许多种方法,都没有解决这个问题。 后面想想,使用其他途径,或许可以解决了我的这个问题,终于功夫不负有心…...

Mysql 学习——项目实战

MySQL 学习——项目实战 项目出处 博主:Asmywishi Linux-Ubuntu启动Mysql sudo mysqlData preparation Create Database and Table Create database : create database mysql_example1;Start database : use mysql_example1;Create Student table : # 学生表…...

Springboot 整合 logback 日志框架

文章目录 整合 Logback 日志框架第一步:导入依赖第二步:导入配置(logback.xml)详解 使用(记录日志) 遇到问题一解决方案 整合 Logback 日志框架 第一步:导入依赖 (Springboot 会自己…...

Hugging face简要介绍

1.注册使用huggingface 2.在Datasets下可以查看数据集 3.在Models下可以查看模型,左侧是对模型的分类 4.官方文档查看https://huggingface.co/docs 5.主要模型: 自回归:GPT、Transformer-XL、XLNet 自编码:BERT、ALBERT、RoBERT…...

A股知识答题pk小程序怎么做?

A股知识答题pk小程序怎么做?以下是制作A股知识答题PK小程序的一般步骤: 一、 需求分析与规划: 明确目标:确定小程序的主要目标,比如是为了帮助用户学习A股知识、进行趣味竞赛,还是作为金融教育工具等。 …...

单细胞转录组 —— kb-python 原始数据处理

单细胞转录组 —— kb-python 原始数据处理 前言 kallisto|bustools 是一种用于预处理 scRNA-seq 数据的工作流程。 数据预处理步骤包括: 将 reads 与其来源细胞关联起来;根据唯一分子标识符(UMI)对 reads 进行去重&#xff1…...

全同态加密算法概览

我们前面有谈到《Paillier半同态加密算法》,半同态加密算法除了支持密文加法运算的 Paillier 算法,还有支持密文乘法计算的 RSA 算法,早期的PSI(隐私求交)和PIR(匿踪查询)都有使用基于RSA盲签名技术来实现。今天我们来谈谈能够有效支持任意函…...

leetcode 刷题day38动态规划Part07 打家劫舍(198.打家劫舍、213.打家劫舍II、337.打家劫舍III)

198.打家劫舍 思路: 1、dp[i]为到第i家偷到的最高金额。 2、如果偷第i家,那么dp[i]dp[i-2]nums[i],如果不偷,则dp[i]dp[i-1],所以递推公式dp[i]max(dp[i-2]nums[i],dp[i-1])。 3、初始值,根据递推公式,我们…...

C0010.Qt5.15.2下载及安装方法

1. 下载及安装 Qt 添加链接描述下载地址:http://download.qt.io/ 选择 archive 目录 安装Qt **注意:**本人使用的是Qt5.15.2版本,可以按如下方法找到该版本;...

制造企业MES管理系统的应用策略与实施路径

在智能制造浪潮的席卷之下,MES管理系统作为连接生产计划与车间操作的核心桥梁,其战略地位愈发显著。本文旨在深入剖析MES管理系统在智能制造转型中的核心价值、实施策略及实践路径,为制造企业探索智能化生产之路提供实践指导与灵感启发。 MES…...

Halcon 3D应用 - 胶路提取

1. 需求 本文基于某手环(拆机打磨处理)做的验证性工作,为了项目保密性,只截取部分数据进行测试。 这里使用的是海康3D线激光轮廓相机直线电机的方式进行的高度数据采集,我们拿到的是高度图亮度图数据。 提取手环上的胶…...

【Redis】Redis线程模型

目录 1. Redis 是单线程的,还是多线程的?2. Redis单线程模式是怎么样的?Redis 单线程模式的优势Redis 单线程的局限性Redis 单线程的优化策略 3. Redis采用单线程为什么还这么快4. Redis 6.0 之前为什么使用单线程?5. Redis 6.0 之…...

Electron构建桌面应用程序,服务于项目的自主学习记录(持续更新...

无所畏惧地面对未知,并将其视为成长的机会 大纲官网快速入门1.安装node.js -- 这里推荐用nvm管理2.脚手架创建3.electron 包安装到应用的开发依赖4.创建主进程(main.js)并启动项目1.创建页面2.配置main.js3.启动项目 -- 效果 进阶 -- 基于项目场景功能使用场景一&am…...

linux Load Average 计算

在内核代码 kernel/sched/loadavg.c 中有一个公式: a1 a0 * e a * (1 - e) 此算法是指数加权移动平均法(Exponential Weighted Moving Average,EMWA),是一种特殊的加权移动平均法,它考虑当前和历史的所有数据&#…...

pandas常用数据格式IO性能对比

前言 本文对pandas支持的一些数据格式进行IO(读写)的性能测试,大数据时代以数据为基础,经常会遇到操作大量数据的情景,数据的IO性能尤为重要,本文对常见的数据格式csv、feather、hdf5、jay、parquet、pick…...

【D3.js in Action 3 精译_031】3.5.2 DIY实战:在 Observable 平台实现带数据标签的 D3 条形图并改造单元测试模块

当前内容所在位置(可进入专栏查看其他译好的章节内容) 第一部分 D3.js 基础知识 第一章 D3.js 简介(已完结) 1.1 何为 D3.js?1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践(上)1.3 数据可…...

华为OD机试真题-字符串分割

题目描述: 给定非空字符串s,将该字符串分割成一些子串,使每个子串的ASCII码值的和均为水仙花数。 1、若分割不成功,则返回0。 2、若分割成功且分割结果不唯一,则返回-1。 3、若分割成功且分割结果唯一,则返…...

编程技巧:提高代码健壮性与可维护性的关键方法(以 Shell 为例)

在脚本编写和自动化工作中,良好的编程技巧对于确保代码的健壮性和可维护性至关重要。以下是一些关键的编程技巧,包括模块化设计、单元测试、版本控制、处理边界条件、错误处理、中间值保存和创建 Flag。本文将通过 Shell 脚本示例来阐述这些技巧的应用。 1. 模块化设计 **定…...

【无标题】ReadableStream is not defined

升级 node 版本到 18 及以上即可解决...