设计模式学习(八)——《大话设计模式》

设计模式学习(八)——《大话设计模式》

单一职责原则

单一职责原则(Single Responsibility Principle, SRP)是软件开发中 SOLID 原则之一,由罗伯特·C·马丁(Robert C. Martin)提出。它指的是一个类应该仅有一个引起它变化的原因,或者更简单地说,一个类应该只负责一项职责。

原则解释

在软件工程中,职责被定义为“变化的原因”。如果一个类有多于一个引起它变化的原因,那么这个类就有多于一个的职责。这违反了单一职责原则。遵循这个原则可以帮助开发者降低系统的复杂性,提高代码的可读性和可维护性,同时也使得系统更加灵活,容易适应变化。

应用实例

假设我们有一个名为 User 的类,它负责用户信息的管理和数据的持久化(例如,保存到数据库)。这个类违反了单一职责原则,因为它有两个引起变化的原因:用户信息的管理变化和数据持久化方式的变化。

为了遵循单一职责原则,我们可以将 User 类分解为两个类:

UserInfo:负责用户信息的管理。
UserPersistence:负责用户数据的持久化。
这样,每个类都只负责一个职责,如果未来用户信息的管理方式改变,只需修改 UserInfo 类;如果持久化方式改变,只需修改 UserPersistence 类。

优点

提高可维护性:当一个类只负责一项任务时,它的复杂性降低,更容易理解和维护。
提高可扩展性:遵循 SRP 的系统更容易扩展,因为新增功能或修改现有功能时影响范围更小。
降低修改带来的风险:修改一个具有单一职责的类时,引入错误的可能性会降低,因为你不需要在同一个类中处理多个任务。

开放-封闭原则

开放封闭原则(Open/Closed Principle, OCP)是面向对象设计原则之一,也是 SOLID 原则中的第二个原则。它由 Bertrand Meyer 提出,主要意思是软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。这意味着一个实体允许其行为被扩展,而无需修改其源代码。

原则解释

对扩展开放:应该能够在不改变现有代码的情况下,为软件实体添加新的功能。
对修改封闭:一旦一个软件实体被发布,它的源代码就不应该被修改,除非修复bug。

应用示例

假设我们正在开发一个绘图程序,需要绘制不同形状。一开始,我们只有圆形和正方形。随着需求的变化,我们可能需要添加更多形状,如三角形、五边形等。

按照开放封闭原则,我们可以设计一个抽象的基类或接口 Shape,定义一个 draw() 方法。然后,为每种形状创建一个子类(如 Circle、Square、Triangle 等),并实现 draw() 方法。当需要添加新形状时,我们只需添加一个新的 Shape 子类并实现 draw() 方法,而无需修改现有代码。

interface Shape {void draw();
}class Circle implements Shape {public void draw() {// 绘制圆形}
}class Square implements Shape {public void draw() {// 绘制正方形}
}class Triangle implements Shape {public void draw() {// 绘制三角形}
}

优点

增强系统的可维护性:遵循开放封闭原则可以减少因新功能引入而对现有代码的修改,从而降低维护成本。
增强系统的可扩展性:系统更容易扩展,因为新增功能时不需要修改现有代码,只需要添加新代码。
促进解耦:通过抽象和多态性可以减少类之间的依赖关系,使系统更加灵活和可维护。

依赖倒转原则

依赖倒转原则(Dependency Inversion Principle, DIP)是 SOLID 设计原则之一,旨在减少类之间的耦合度,提高系统的灵活性和可维护性。

依赖倒转原则有两个核心要点:

  • 高层模块不应该依赖于低层模块。两者都应该依赖于抽象。

  • 抽象不应该依赖于具体实现。具体实现应该依赖于抽象。

解释

依赖倒转原则的主要目的是通过依赖抽象而不是具体实现,来降低类之间的耦合度。这意味着代码的高层策略不应该由底层的实现细节所影响,从而使得修改底层实现时不需要修改依赖于它的高层模块。

应用实例

假设我们有一个应用程序,其中包含一个按钮类(Button)和一个灯类(Lamp),按钮被按下时灯会切换状态(开/关)。如果按钮直接依赖于灯的具体实现,那么每当我们想要按钮控制其他设备时,都需要修改按钮的代码。

为了遵循依赖倒转原则,我们可以引入一个抽象的设备接口(Device),让灯类实现这个接口。按钮类依赖于设备接口,而不是具体的灯类。这样,按钮类就可以控制任何实现了设备接口的对象,而无需修改按钮类的代码。

interface Device {void toggle();
}class Lamp implements Device {public void toggle() {// 实现开关灯}
}class Button {private Device device;public Button(Device device) {this.device = device;}public void press() {device.toggle();}
}

优点

降低耦合度:依赖倒转原则通过促使模块间依赖抽象而非具体实现,降低了模块间的耦合度。
提高可维护性:系统中的高层模块不再需要知道底层模块的具体实现细节,使得系统更易于扩展和维护。
增强灵活性:更换或增加新的实现时,不需要修改依赖于抽象的高层模块,提高了系统的灵活性。

里氏代换原则

里氏代换原则(Liskov Substitution Principle, LSP)是 SOLID 设计原则之一,由芭芭拉·里氏(Barbara Liskov)在1987年提出。这个原则的核心思想是:在软件中,如果类 S 是类 T 的子类,那么类型 T 的对象可以被类型 S 的对象替换(即类型 S 的对象可以作为类型 T 的对象使用),而不改变程序的期望行为(正确性、任务执行等)。

原则解释

里氏代换原则要求子类能够替换掉它们的父类并且出现在父类能够出现的任何地方,而不破坏程序的正确性。这意味着子类在扩展父类的行为时,不能改变父类原有的行为。

应用示例

假设我们有一个矩形类和一个正方形类,正方形是矩形的一个特例。根据里氏代换原则,正方形应该能够替换矩形。但是,如果矩形类有设置宽度和高度的方法,而正方形类继承了这些方法,这将违反里氏代换原则,因为改变正方形的宽度会同时改变它的高度,这与矩形的行为不一致。

class Rectangle {protected int width, height;public void setWidth(int width) {this.width = width;}public void setHeight(int height) {this.height = height;}public int getArea() {return width * height;}
}class Square extends Rectangle {public void setWidth(int width) {this.width = this.height = width;}public void setHeight(int height) {this.width = this.height = height;}
}

在这个例子中,Square 类违反了里氏代换原则,因为它改变了 Rectangle 类的行为。正确的做法是重构这些类,以确保它们遵循里氏代换原则。

优点

遵循里氏代换原则可以增强程序的健壮性,提高代码的可读性和可维护性,并且能够确保继承体系的正确性。此外,它还促进了代码的复用。

装饰模式

装饰模式(Decorator Pattern)是一种结构型设计模式,它允许用户通过将对象放入包含行为的特殊封装对象中来为单个对象动态地添加新的行为,而不改变其结构。这种模式创建了一个装饰类,用来包装原有的类,并在保持原类方法签名完整性的前提下,提供了额外的功能。

原理

装饰模式主要利用组合和继承的技术来实现。它包含以下几个角色:

  • 抽象组件(Component):定义了一个对象接口,可以给这些对象动态地添加职责。
  • 具体组件(ConcreteComponent):定义了抽象组件的具体实现,即被装饰的具体对象。
  • 装饰角色(Decorator):持有一个组件(Component)对象的引用,并定义了与抽象组件接口一致的接口。
  • 具体装饰(ConcreteDecorator):负责给组件添加新的职责。

应用示例

假设我们有一个简单的文本消息类,我们想要不修改其代码的情况下,增加一些额外功能,比如加密和压缩。这时,我们可以使用装饰模式来实现:

// 抽象组件
interface Message {String getContent();
}// 具体组件
class TextMessage implements Message {private String content;public TextMessage(String content) {this.content = content;}@Overridepublic String getContent() {return content;}
}// 装饰角色
abstract class MessageDecorator implements Message {protected Message message;public MessageDecorator(Message message) {this.message = message;}
}// 具体装饰 - 加密装饰
class EncryptMessageDecorator extends MessageDecorator {public EncryptMessageDecorator(Message message) {super(message);}@Overridepublic String getContent() {// 实现加密功能return encrypt(message.getContent());}private String encrypt(String content) {return "encrypted(" + content + ")";}
}// 具体装饰 - 压缩装饰
class CompressMessageDecorator extends MessageDecorator {public CompressMessageDecorator(Message message) {super(message);}@Overridepublic String getContent() {// 实现压缩功能return compress(message.getContent());}private String compress(String content) {return "compressed(" + content + ")";}
}

在示例中,TextMessage 是一个具体组件,EncryptMessageDecorator 和 CompressMessageDecorator 是具体装饰。通过这种方式,我们可以在不修改 TextMessage 类的情况下,为其动态添加加密和压缩等功能。

优点

  • 提高类的扩展性:在不修改原有对象的基础上,通过使用不同的装饰类以及这些装饰类的排列组合,可以实现不同效果。
  • 动态添加功能:装饰模式提供了一种灵活的替代扩展系统功能的方法,可以在运行时添加或删除功能。
  • 符合开闭原则:系统可以在不修改原有代码的情况下引入新的功能,满足开闭原则。

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

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

相关文章

Could not find the Qt platform plugin “dxcb“ in ““、 重点:是dxcb

这个重点就在于是dxcb不是xcb,让我一顿好找。 https://bugs.launchpad.net/ubuntu/source/deepin-qt5dxcb-plugin/bug/1826629 这篇文章描述了应该是deepin系统的一个问题,应该已经修复了不知道为什么我还会遇到。 不过知道是dxcb后直接去qtcreater里的系…

ROS 2边学边练(45)-- 构建一个能动的机器人模型

前言 在上篇中我们搭建了一个机器人模型(其由各个关节(joint)和连杆(link)组成),此篇我们会通过设置关节类型来实现机器人的活动。 在ROS中,关节一般有无限旋转(continuous),有限旋转…

Android 注解

自定义注解 注解原理 注解本质是一个接口,Java中所有注解都是继承了Annotation接口的 注解(…):其实就是一个实现类对象,实现了该注解以及Annotation接口。

TB交易开拓者旗舰版自动交易的设置

本文针对TB交易开拓者旗舰版V6.0.7.0(期货程序化交易软件下载 - 交易开拓者),目前网上没有自动交易设置的完整教程,特写此篇。 1. 设置期货账户的自动登录和登出。点击菜单“文件/系统设置”,然后在“安全”tab做如下设置: 2 设置你的期货账…

C++向函数传递对象

C语言中,对象作为函数的参数和返回值的传递方式有 3 种:值传递、指针传递和引用传递。 1. 对象作为函数参数 把实参对象的值复制给形参对象,这种传递是单向的,只从实参到形参。因此,函数对形参值做的改变不会影响到实…

Sybase数据库分页查询(指定起始位置)

针对单表数据量过大的场景,分页查询必不可少。针对sybase数据库分页查询的案例全网稀少,特别是指定起始页的分页查询实现。 本文依靠实际开发场景,特此总结Sybase数据库分页查询(指定起始位置)。 目录 一、 SQL实现分…

视频号小店不直播怎么出单?这里面的秘密,一篇文章全曝光!

大家好,我是电商糖果 这两年关于视频号搞电商的话题度非常高,也吸引了很多商家入驻。 视频号因为背后巨大的私域流量池扶持,所以它的转化率非常高。 根据官方发出来的战报,我们也可以看出它的数据是翻倍增长。 在2024微信公开…

git对远程和本地分支进行重命名

要同时对Git的远程和本地分支进行重命名,你需要分几个步骤操作: 重命名本地分支 切换到其他分支:在重命名当前分支之前,确保你不在你想要重命名的那个分支上。你可以通过以下命令切换到另一个分支(比如切换到master分…

5.06号模拟前端面试8问

5.06号模拟前端面试8问 1.promise如何实现then处理 在JavaScript中,Promise 是一个代表异步操作最终完成或失败的对象。它有三种状态:pending(等待),fulfilled(完成),rejected&…

红日靶场ATTCK攻击合集

工作繁忙,笔记更新的有比较慢,转到CSDN同步更新很麻烦,直接看原始的笔记吧。不足之处欢迎多多指点。 已经打完的靶场如下: 红日靶场ATT&CK1:https://blog.csdn.net/weixin_44288604/article/details/108172737红…

Java面试题:描述Exchanger类的用途以及如何用它来交换数据

在编程中,Exchanger 类通常是Java并发编程中用于线程间数据交换的一个类。它属于java.util.concurrent包,提供了一种在两个线程之间进行数据交换的机制。使用Exchanger,两个线程可以交换数据,每个线程都可以提供数据并接收对方的数…

【漏洞复现】GB28181摄像头管理平台api接口处存在未授权漏洞

免责声明:文章来源互联网收集整理,请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该…

faad2交叉编译——aac解码为pcm,解决faad单通道转双通道问题

FAAD是比较成熟高效的开源AAC解码库,这里用于解码AAC生成PCM数据,用于音频播放。这里因为faad库,会将单通道转化为双通道踩了些坑,所以记录一下。 我使用的是2.11.0版本,貌似往前的版本没有使用CMake,需要c…

C++中如何自己封装一个Callable

需求背景 有时候静态编译太不灵活,我们需要更灵活的运行时操作。 又或真假设你在开发一个脚本,想注册本地的C函数到脚本语言的标准库中。例如gdscript的Callable。 下面是一个我的一个简单的实现。我们假设脚本语言中的变量类型是std::any。根据情况不…

《Fundamentals of Power Electronics》——一些常用变换器的正则电路参数值

对于理想的CCM PWM dc-dc转换器,其包含一个电感和电容,正则模型有效的低通滤波器需要包含一个电感和一个电容。正则模型简化为如下图所示。 假设电容与负载直接相连。基础的buck、boost和buck-boost转换器的参数值如下表所示。 该模型可以用传统的线性电…

使用网站内容进行多渠道品牌营销的主要优势

在选择服务提供商时,人们使用不同的方式来查找信息并与他们联系。有些人更喜欢网站,有些人则使用社交媒体或电子邮件。网站对于数字存在仍然至关重要,但跨多个渠道管理内容现在至关重要。多渠道营销以客户喜欢的方式与客户建立联系&#xff0…

记住这篇!论文查重降重aigc降低一定要看!

论文查重率降不下去真是受不了啊!根本降不下去!这些方法工具太适合我这样的论文裁缝了! 一、论文降重/aigc降低工具 如果实在降不下去可以使用“蝌蚪论文”和“反向词典”这两个工具,也是我最常用的降重软件。 1.蝌蚪论文&#xf…

我从这些书籍中学来的财务以及税务知识

“你不能指望在开始工作的头两年攒下任何积蓄。” 这句话一直是我的座右铭,也是我给大学生的个人理财建议。这也就难怪我二十出头的时候,基本就是靠薪水过日子。 回想起来,我意识到其实这并不是最好的建议,甚至非常不好。 我现…

区块链的应用场景以及解释为什么能够保证安全提高信任度

区块链的不可篡改性和透明性是其最重要的特征之一。 不可篡改性:是指一旦数据被写入区块链,就无法被修改或删除。这是因为区块链中的每个区块都包含了前一个区块的哈希值,这个哈希值与当前区块的数据一起计算得出。如果对当前区块的数据进行…

BigInteger和BigDecimal类

BigInteger 和 BigDecimal 介绍 应用场景 BigInteger适合保存比较大的整型BigDecimal适合保存精度更高的浮点型(小数) BigInteger 和 BigDecimal 常见方法 1,add 加2,subtract 减3,multiply 乘4,divide…