设计模式六大原则:面向对象设计的核心

在面向对象编程(OOP)中,设计模式为编写高效、可维护且可扩展的代码提供了重要指导。而这背后的核心是设计模式中的六大原则。本文将详细介绍这些原则,并使用Java代码实例进行说明。


1. 单一职责原则(Single Responsibility Principle, SRP)

通俗解释:
每个人只做自己分内的事,不要什么都想做。一个类只负责一个功能,不要让它承担太多职责。如果一个类既管账又做市场推广,那以后改起来会很麻烦。

原则说明:
单一职责原则要求一个类应该只有一个引起它变化的原因。换句话说,类应该专注于完成一个职责。将多个职责混合在同一个类中会导致类的复杂度增加,维护起来更加困难。

Java 代码示例:

class User {private String name;private String email;public User(String name, String email) {this.name = name;this.email = email;}public void save() {System.out.println("Saving user " + name + " to the database");}public void log(String message) {System.out.println("Log: " + message);}
}

上面代码违反了单一职责原则,因为User类既负责用户信息的保存,又负责日志记录。为了遵守SRP,可以把日志功能分离到一个单独的Logger类中:

class Logger {public void log(String message) {System.out.println("Log: " + message);}
}class User {private String name;private String email;private Logger logger;public User(String name, String email) {this.name = name;this.email = email;this.logger = new Logger();}public void save() {System.out.println("Saving user " + name + " to the database");logger.log("User " + name + " saved successfully");}
}

通过分离日志和用户信息保存的职责,每个类只专注于一个职责,从而提高了代码的可维护性。


2. 开闭原则(Open-Closed Principle, OCP)

通俗解释:
新的需求来了,咱们应该在不动老代码的前提下,尽量通过“扩展”来增加新功能,而不是改动现有的东西。就像装修房子的时候,尽量别砸老墙,只在新地方加点装饰。

原则说明1:
开闭原则要求软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。也就是说,添加新功能时不应该修改已有的代码,而是通过扩展实现。

原则说明2:

开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

Java 代码示例:

假设我们有两个类来计算不同形状的面积:

class Rectangle {private double width, height;public Rectangle(double width, double height) {this.width = width;this.height = height;}public double area() {return width * height;}
}class Circle {private double radius;public Circle(double radius) {this.radius = radius;}public double area() {return Math.PI * radius * radius;}
}

现在,如果需要添加三角形面积计算,不应该修改原有代码,而是通过扩展:

class Triangle {private double base, height;public Triangle(double base, double height) {this.base = base;this.height = height;}public double area() {return 0.5 * base * height;}
}

通过增加新的类而不修改现有类,符合开闭原则。


3. 里氏替换原则(Liskov Substitution Principle, LSP)

通俗解释:
子类应该能在任何地方都替代父类,并且表现良好。就好比用不同牌子的手机充电器,你只要插上就能用,而不会影响充电效果,不会突然坏掉。

原则说明1:
里氏替换原则要求子类对象必须能够替换其父类对象,并且程序的行为不会受到影响。即子类必须保持与父类兼容的行为。

原则说明2:
里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

Java 代码示例:

假设我们有一个Bird类,以及SparrowPenguin类:

class Bird {public void fly() {System.out.println("Bird is flying");}
}class Sparrow extends Bird {@Overridepublic void fly() {System.out.println("Sparrow is flying");}
}class Penguin extends Bird {@Overridepublic void fly() {System.out.println("Penguin can't fly");}
}

Penguin类不能飞,但是Bird类的定义要求子类能够飞,这违反了里氏替换原则。我们可以将“飞行”的概念抽象为一种行为,避免不适用的行为继承:

abstract class Bird {public abstract void move();
}class Sparrow extends Bird {@Overridepublic void move() {System.out.println("Sparrow is flying");}
}class Penguin extends Bird {@Overridepublic void move() {System.out.println("Penguin is swimming");}
}

通过这样设计,每个子类可以按照自己的特性定义“移动”行为,符合LSP。


4. 依赖倒置原则(Dependency Inversion Principle, DIP)

通俗解释:
老板不要直接管理具体的员工,而是通过经理(抽象的接口)来下达指令。这样,员工换了没关系,经理还在,工作还能正常进行。我们应该依赖“接口”而不是“具体实现”。

原则说明1:
依赖倒置原则要求高层模块不应该依赖于低层模块,二者都应该依赖于抽象。这个原则的核心在于使用接口或抽象类,而不是直接依赖具体实现。

原则说明2:
这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。

Java 代码示例:

假设我们有一个EmailService类,它提供发送邮件的功能:

class EmailService {public void sendEmail(String message) {System.out.println("Sending email: " + message);}
}class Notification {private EmailService emailService;public Notification(EmailService emailService) {this.emailService = emailService;}public void notify(String message) {emailService.sendEmail(message);}
}

这种设计违反了DIP,因为Notification类依赖于具体的EmailService实现。我们可以通过引入接口进行改进:

interface MessageService {void sendMessage(String message);
}class EmailService implements MessageService {@Overridepublic void sendMessage(String message) {System.out.println("Sending email: " + message);}
}class SMSService implements MessageService {@Overridepublic void sendMessage(String message) {System.out.println("Sending SMS: " + message);}
}class Notification {private MessageService messageService;public Notification(MessageService messageService) {this.messageService = messageService;}public void notify(String message) {messageService.sendMessage(message);}
}

通过依赖接口而不是具体类,我们可以轻松切换不同的消息服务(如SMS或Email),符合依赖倒置原则。


5. 接口隔离原则(Interface Segregation Principle, ISP)

通俗解释:
不要让一个人负责太多不相关的事情,接口也是一样,不要把一大堆不相关的方法放在一个接口里。每个人负责自己该做的事情就好,比如,一个人既要修车又要做饭,显然不合理。

原则说明1:
接口隔离原则要求客户端不应该依赖它不需要的接口。即接口应该尽可能小,确保客户端只依赖于它实际需要的方法。

原则说明2:
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。

Java 代码示例:

假设我们有一个Worker接口,它既包含工作职责,也包含吃饭的职责:

interface Worker {void work();void eat();
}

如果有些工人不需要eat方法,这个设计就违反了接口隔离原则。我们可以将接口分离:

interface Workable {void work();
}interface Eatable {void eat();
}

这样,只有需要吃饭功能的类才会实现Eatable接口,符合ISP原则。


6. 迪米特法则(Law of Demeter, LoD)

通俗解释:
少打听别人的隐私,保持一定的“距离感”。一个类不需要知道其他类的太多细节,只需要知道自己该怎么用其他类公开的功能就好了,避免太过“亲密”导致耦合度太高。

原则说明1:
迪米特法则要求一个对象应尽量少了解其他对象的细节。也就是说,一个类应该尽量减少与其他类的直接交互,只与必要的对象交互。

原则说明2:
也叫最少知道原则:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。

Java 代码示例:

class Engine {public void start() {System.out.println("Engine started");}
}class Car {private Engine engine;public Car() {engine = new Engine();}public void start() {engine.start();}
}

在这个例子中,Car类只与Engine类交互,并且只使用Engine提供的公开方法,而不涉及其内部实现细节,符合迪米特法则。


结论

设计模式的六大原则是面向对象设计的基石。通过遵循这些原则,开发者可以编写出更易维护、扩展性更强的代码。理解和应用这些原则对于提高代码质量和降低系统复杂性至关重要。

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

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

相关文章

DERT目标检测—End-to-End Object Detection with Transformers

DERT:使用Transformer的端到端目标检测 论文题目:End-to-End Object Detection with Transformers 官方代码:https://github.com/facebookresearch/detr 论文题目中包括的一个创新点End to End(端到端的方法)简单的理解就是没有使…

MISC - 第四天(OOK编码,audacity音频工具,摩斯电码,D盾,盲文识别,vmdk文件压缩)

前言 各位师傅大家好,我是qmx_07,今天继续讲解MISC知识点 FLAG 附件是一张图片,尝试binwalk无果 使用StegSolve工具Data Extract查看时 发现PK字段,是大多数压缩包的文件头点击Save Bin保存zip文件 解压缩失败使用修复软件:htt…

代码随想录Day17 图论-2

103. 水流问题 本题思路很简单 要求我们找到可以满足到达两个边界的单元格的坐标 有一个优化的思路就是 我们从边界的节点向中间遍历 然后用两个数组表示 一个是第一组边界的数组 一个是第二边界的数组 如果两个数组都遍历到了某一个单元格 就说明该单元格时满足题目要求的 #…

OpenLayers 开源的Web GIS引擎 - 添加地图控件地图控件

中心点按钮、地图放大缩小滑块、全图和比例尺控件 直接上代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.…

如何选择适合的干式电抗器?

干式电抗器是电力系统中重要的电气设备&#xff0c;主要用于限制电网中的短路电流&#xff0c;提高电力系统的稳定性和可靠性。选择适合的干式电抗器对于保障电力系统的正常运行具有重要意义。以下是选择适合的干式电抗器的一些建议&#xff1a; 1. 根据电力系统的需求选择合适…

大模型算法岗常见面试题100道(值得收藏)非常详细收藏我这一篇就够了

大模型应该是目前当之无愧的最有影响力的AI技术&#xff0c;它正在革新各个行业&#xff0c;包括自然语言处理、机器翻译、内容创作和客户服务等等&#xff0c;正在成为未来商业环境的重要组成部分。 截至目前大模型已经超过200个&#xff0c;在大模型纵横的时代&#xff0c;不…

【设计模式】创建型模式(四):建造者模式

《设计模式之创建型模式》系列&#xff0c;共包含以下文章&#xff1a; 创建型模式&#xff08;一&#xff09;&#xff1a;工厂模式创建型模式&#xff08;二&#xff09;&#xff1a;抽象工厂模式创建型模式&#xff08;三&#xff09;&#xff1a;单例模式创建型模式&#…

Android14请求动态申请存储权限

Android14请求动态申请存储权限 Android14和Android15存储权限有增加多了选择部分&#xff0c;还是全部。一个小小的存储权限真的被它玩出了花来。本来Android13就将存储权限进行了3个细分&#xff0c;是图片&#xff0c;音频还是视频文件。 步骤一&#xff1a;AndroidManife…

峟思:山洪灾害监测预警系统全面解析

在自然灾害频发的今天&#xff0c;山洪灾害以其突发性强、破坏力大而备受关注。为了有效预防和减少山洪灾害带来的损失&#xff0c;山洪灾害监测预警系统应运而生。本文将详细介绍该系统的主要组成部分、关键传感器及其工作机制&#xff0c;以期为防灾减灾工作提供有力支持。 山…

项目小总结

这段时间主要把大概的开发流程了解完毕 修改了&#xff0c;并画了几个界面 一.界面 修改为 博客主页 个人中心 二.前后端分离开发 写前端时 就可以假设拿到这些数据了 const blogData2 {blog:{id:1,title: "如何编程飞人",author_id: 1,content: "这是一篇…

最新版C/C++通过CLion2024进行Linux远程开发保姆级教学

目前来说&#xff0c;对Linux远程开发支持相对比较好的也就是Clion和VSCode了&#xff0c;这两个其实对于C和C语言开发都很友好&#xff0c;大可不必过于纠结使用那个&#xff0c;至于VS和QtCreator&#xff0c;前者太过重量级了&#xff0c;后者更是不用说&#xff0c;主要用于…

【论文阅读】Grounding Language with Visual Affordances over Unstructured Data

Abstract 最近的研究表明&#xff0c;大型语言模型&#xff08;llms&#xff09;可以应用于将自然语言应用于各种各样的机器人技能。然而&#xff0c;在实践中&#xff0c;学习多任务、语言条件机器人技能通常需要大规模的数据收集和频繁的人为干预来重置环境或帮助纠正当前的…

vue node node-sass sass-loader 版本 对应 与 兼容

警告&#xff1a; LibSass 和 Node Sass 已弃用。虽然它们将继续无限期地接收维护版本&#xff0c;但没有计划添加其他功能或与任何新的 CSS 或 Sass 功能兼容。仍在使用它的项目应该转移到 Dart Sass。 sass Sass是一种预处理器脚本语言&#xff0c;可以解释或编译成…

Java—反射机制详解

介绍反射 反射的基本概念 反射&#xff08;Reflection&#xff09;是Java语言中的一种机制&#xff0c;它允许程序在运行时检查和操作类、接口、字段和方法等类的内部结构。通过反射&#xff0c;你可以在运行时获取类的信息&#xff0c;包括类的构造器、字段、方法等&#xf…

在 Windows 上运行 Vue 项目时解决 ‘NODE_OPTIONS‘ 错误

在 Windows 上运行 Vue 项目时解决 ‘NODE_OPTIONS’ 错误 在 Windows 系统上启动 Vue 项目时&#xff0c;遭遇报错。具体报错信息如下&#xff1a; ‘NODE_OPTIONS‘ 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。这个错误通常意味着 Windows 系统无法识…

机器翻译之创建Seq2Seq的编码器、解码器

1.创建编码器、解码器的基类 1.1创建编码器的基类 from torch import nn#构建编码器的基类 class Encoder(nn.Module): #继承父类nn.Moduledef __init__(self, **kwargs): #**kwargs&#xff1a;不定常的关键字参数super().__init__(**kwargs)def forward(self, X, *args…

基于SpringBoot+Vue+MySQL的美食点餐管理系统

系统展示 用户前台界面 管理员后台界面 系统背景 在数字化快速发展的今天&#xff0c;餐饮行业也迎来了转型升级的重要机遇。传统餐饮管理方式面临效率低下、顾客体验不佳等问题。为此&#xff0c;开发一款基于SpringBootVueMySQL架构的美食点餐管理系统显得尤为重要。该系统旨…

【可图(Kolors)部署与使用】大规模文本到图像生成模型部署与使用教程

✨ Blog’s 主页: 白乐天_ξ( ✿&#xff1e;◡❛) &#x1f308; 个人Motto&#xff1a;他强任他强&#xff0c;清风拂山冈&#xff01; &#x1f4ab; 欢迎来到我的学习笔记&#xff01; 1.Kolors 简介 1.1.什么是Kolors&#xff1f; 开发团队 Kolors 是由快手 Kolors 团队…

网页护眼宝——全方位解析 Chrome Dark Reader 插件

网页护眼宝——全方位解析 Chrome Dark Reader 插件 1. 基本介绍&#xff1a;Chrome 插件的力量与 Dark Reader 的独特之处 随着现代浏览器的功能越来越强大&#xff0c;Chrome 插件为用户提供了极大的定制化能力。从广告屏蔽、性能优化到页面翻译&#xff0c;Chrome 插件几乎…

视频监控相关笔记

一、QT 之 QTreeWidget 树形控件 Qt编程指南&#xff0c;Qt新手教程&#xff0c;Qt Programming Guide 一个树形结构的节点中的图表文本 、附带数据的添加&#xff1a; QTreeWidgetItem* TourTreeWnd::InsertNode(NetNodeInfo node, QTreeWidgetItem* parent_item) { // …