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

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

单一职责原则

单一职责原则(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;
    }

    @Override
    public 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);
    }

    @Override
    public String getContent() {
        // 实现加密功能
        return encrypt(message.getContent());
    }

    private String encrypt(String content) {
        return "encrypted(" + content + ")";
    }
}

// 具体装饰 - 压缩装饰
class CompressMessageDecorator extends MessageDecorator {
    public CompressMessageDecorator(Message message) {
        super(message);
    }

    @Override
    public String getContent() {
        // 实现压缩功能
        return compress(message.getContent());
    }

    private String compress(String content) {
        return "compressed(" + content + ")";
    }
}

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

优点

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第一课为SimaPro的基本特征

问题: 咖啡机的设计中的环境影响指标。 step 1 点击Wizards,看到“Guided tour (with coffee)”。 在这个例子里, 定义了两种咖啡机: Sima型咖啡机 和 Pro型咖啡机, 具有以下规格: Sima型咖啡机 Pro型咖啡…

MySQL——Windows平台下MySQL安装与配置(一)MySQL安装

Windows平台下安装和配置 基于Windows平台的MySQL安装文件有两个版本,一种是以.msi作为后缀名的二进制分发版,一种是以.zip作为后缀的压缩文件。其中.msi的安装文件提供了图形化的安装向导,按照向导提示进行操作即可安装完成,.zip…

7-92 骨牌铺方格

在2n的一个长方形方格中,用一个12的骨牌铺满方格,输入n,输出铺放方案的总数。例如n3时,骨牌的铺放方案有3种,如下图所示。 输入格式: 测试数据有多组,处理到文件尾。每组测试输入一个整数n(0&l…

【华为】AC直连二层组网隧道转发实验配置

【华为】AC直连二层组网隧道转发实验配置 实验需求拓扑配置AC数据规划表 AC的配置顺序AC1基本配置(二层通信)AP上线VAP组关联--WLAN业务流量 LSW1AR1STA获取AP的业务流量 配置文档 实验需求 AC组网方式:直连二层组网。 业务数据转发方式:隧道转发。 DHC…

[JUCE]从一个有关右值引用的bug,探幽移动语义

一、问题 当我尝试在\JUCE\extras\WindowsDLL\Builds\VisualStudio2022目录下编译JUCE库的时候,提示报错如下: 报错提示如下: 这里涉及到两个问题 一、这个std::move是干嘛用的 二、为什么这里会报错? 另外,我在实…

Mybatis进阶2

Mybatis进阶1-CSDN博客 Mybatis入门-CSDN博客 Mybatis入门2-CSDN博客 我们接下来要学习Mybatis的高级查询 我们先在数据库中准备我们需要的数据表 teacher表 课程表:与教师表是一对多的关系,所以有一个外键字段 学生表 由于学生表和课程表是多对多的…

Android selinux权限

一.SE 概述 SELinux 是由美国NSA(国安局)和 SCC 开发的 Linux的一个扩张强制访问控制安全模块。原先是在Fluke上开发的,2000年以 GNU GPL 发布。从 fedora core 2开始, 2.6内核的版本都支持SELinux。 在 SELinux 出现之前&#…

智慧公厕打造公共厕所智慧化管理模式

智慧公厕如何打造智慧化的管理模式?随着智能科技的快速发展,智慧公厕成为了城市管理的一项重要工作。智慧公厕的智能化管理不仅可以提升公厕的整体管理水平,还能为市民提供更加便捷、舒适的使用体验。本文将以智慧公厕源头实力厂家广州中期科…

Qt QImageWriter类介绍

1.简介 QImageWriter 用于写入图像文件的类。它提供了将 QImage 对象保存到不同图像格式文件的功能,包括但不限于 PNG、JPEG、BMP 等。QImageWriter 可以将图像写入文件,也可以写入任何 QIODevice,如 QByteArray,这使得它非常灵活…

CGAL 网格简化

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 为了提高网格处理的效率,通常需要将过于冗长的3D数据集简化为更简洁而又真实的表示。尽管从几何压缩到逆向工程有许多应用,但简洁地捕捉表面的几何形状仍然是一项乏味的任务。CGAL中则为我们提供了一种通过变分几…

MSYS2 Pacman常用命令--以及实际中安装linux命令

MSYS2 Pacman常用命令--以及实际中安装linux命令: 有时候需要使用linux下的命令,用这个工具就是可以实现内容 虽然现在在windows下的wsl命令以及可以很好的使用linux了,但是MSYS2也是个不错的工具: 如何下载linux下nc&#xff0c…

Nodejs-内存控制(垃圾回收机制)(新生代老生代)(Scavenge算法)

内存控制 v8的垃圾回收机制和内存限制 对于性能敏感的服务器端程序,内存管理的好坏,垃圾回收状态的优良成都,都会对服务器造成影响 Node和V8 Node在JavaScript的执行上受益于v8,随着v8的升级享受到更好的性能和性的语言特征。…

详解基于 RAG 的 txt2sql 全过程

前文 本文使用通义千问大模型和 ChromaDB 向量数据库来实现一个完整的 text2sql 的项目,并基于实际的业务进行效果的展示。 准备 在进行项目之前需要准备下面主要的内容: python 环境通义千问 qwen-max 模型的 api-keyChromaDB 向量数据库acge_text_…

一款 NodeJS 版本管理工具 NVM (Windows)

一、简介 Node Version Manager(NVM)是一种用于管理多个 NodeJS 版本的工具。在日常工作中,我们可能同时在进行多个不同的项目开发,每个项目的需求不同,依赖与不同版本的NodeJS 运行环境。这种情况下,维护…

数据处理学习笔记9

一些其他的函数 “Resize”和“Reshape”的区别主要在于它们对数组元素数量和形状的处理方式不同,以下是详细介绍: “Resize”通常会改变数组的元素数量,在放大数组形状时会用0补全新增的元素,而在缩小数组形状时会丢弃多余的元素…

一款AI工作流项目:phidatahq/phidata

一款AI工作流项目:phidatahq/phidata 构建和测试功能强大的 AI 工作流程。该项目提供了一个工作流平台,可以结合大型语言模型(LLM)和各种工具,扩展模型的实用性和应用范围。[1][4][5] 开发各种 AI 助手应用,如客服聊天机器人、数据分析工具、研究助手等。phidata 提…

Golang | Leetcode Golang题解之第72题编辑距离

题目&#xff1a; 题解&#xff1a; func minDistance(word1 string, word2 string) int {m, n : len(word1), len(word2)dp : make([][]int, m1)for i : range dp {dp[i] make([]int, n1)}for i : 0; i < m1; i {dp[i][0] i // word1[i] 变成 word2[0], 删掉 word1[i], …

LabVIEW波浪发电平台浮筒取能效率数据采集系统

LabVIEW波浪发电平台浮筒取能效率数据采集系统 随着化石能源的逐渐减少以及能源价格的上升&#xff0c;寻找可替代的、可再生的、清洁的能源成为了世界各国的共识。波浪能作为一种重要的海洋能源&#xff0c;因其巨大的潜力和清洁性&#xff0c;近年来受到了广泛关注。开发了一…

32 OpenCV Harris角点检测

文章目录 cornerHarris 算子示例 角点检测 cornerHarris 算子 void cv::cornerHarris ( InputArray src,OutputArray dst,int blockSize,int ksize,double K,int borderType BORDER_DEFAULT) src:待检测Harris角点的输入图像&#xff0c;图像必须是CV 8U或者CV 32F的单通道…

玩comfyui踩过的坑之使用ComfyUI_Custom_NODES_ALEKPET翻译组件问题

环境&#xff1a; 秋叶安装包&#xff0c;安装ComfyUI_Custom_NODES_ALEKPET组件或者直接下载网盘中的包&#xff0c;直接解压包到comfyui根目录/custom_nodes/&#xff0c;重启后&#xff0c;按指导文件操作。 注意&#xff1a;网盘指导包中有配置好的流程json文件&#xff0…
最新文章