软件设计的“SOLID”五大原则

news2024/11/17 21:22:49

一、单一职责

1、定义

单一职责原则(single Responsibility Principle,SRP)规定,每一个软件单元,其中包括组件、类和函数,应该只有一个单一且明确定义的职责。

2、特点

一个类应该仅有一个引起它变化的原因;

变化的方向隐含着类的责任;

遵循SRP的类通常很小而且具有很少的依赖性。它们清晰、易于理解,并且非常容易测试。

职责是一个比类的代码行数更好的标准。一个类可以有100、200甚至500行,如果这些类没有违反单一职责原则,那就完全没有问题。尽管如此,高LOC还是可以作为一个指标,它暗示:你应该注意这些类!也许一切都很好,但也许太大了,因为它们有更多的职责。

二、开放封闭原则

1、定义

所有的系统在其生命周期内都会发生变化。在开发预期比第一个版本持续时间更长的系统时,必须注意这一点。

——Ivar Jaocbson,Swedish computer scientist,1992    OCP(Open Close Principle)

2、特点

对扩展开放,对更改封闭;

类模块应该是可扩展,但是不可修改;

软件系统将随着时间的推移而发展,这是一个简单的事实。必须满足不断增加的新需求,并且现有的需求一定会随着客户的需求或技术的进度而不断改变。这些扩展不仅应该以优雅的方式实现,而且应该以尽可能小的代价完成,它们最好是在不需要更改现有代码的基础上被实现。如果任何新的需求都会导致软件现有且已经经过充分测试的部分发生一连串的变化和调整,那将是致命的。

在面向对象中,支持这一原则的一种方法就是继承。通过继承,可以在不修改类的情况下向类添加新功能。此外,还有许多面向对象的设计模式也支持OCP,例如策略模式或装饰器模式

三、里氏替换原则

1、定义

LSP(Liskov Substitution Principle

> 子类必须能够替换它们的基类(is-a)。

> 继承表达类型抽象。

2、规则

里氏替换原则分别为类层次结构制定了一下规则:

> 基类的前置条件不能在派生类中增强。

> 基类的后置条件不能在派生类中被削弱,也就是说派生类方法的后置条件(即方法的返回值)要比父类更严格。

> 基类的所有不变量(包括数据成员和函数成员)都不能通过派生子类更改或违反。

> 历史约束(即“历史规则”):对象的(内部)状态只能通过公共接口(封装)中方法调用来改变。由于派生类可能引入基类中不存在的新属性和方法,因此这些方法可能运行派生类的对象更改基类中那些不允许被改变的状态。所谓的历史约束就是禁止这一点。

3、需求

3.1、需求1

开发一个具有基本形状类型的类库,例如,Circle、Rectangle、Triangle和TextLabel。

UML类图设计如下:

 代码实现如下:

#include<memory>
#include<vector>
#include<string>
#include<iostream>
using namespace std;

class Point final
{
public:
	Point() :x{ 5 }, y{ 10 }{}
	Point(const uint16_t int_x, const uint16_t int_y) {
		x = int_x;
		y = int_y;
	}
private:
	uint16_t x;
	uint16_t y;
};

class Shape
{
public:
	Shape() :isVisible{ false } { }
	virtual ~Shape() = default;
	void moveTo(const Point& newCenterPoint) {
		hide();
		centerPoint = newCenterPoint;
		show();
	}
	virtual void show() { 
		isVisible = true; 
		std::cout << "--------show Shape---------" << std::endl;
	}
	virtual void hide() { 
		isVisible = false; 
		std::cout << "--------hide Shape---------" << std::endl;
	}
private:
	Point centerPoint;
	bool isVisible;
};

class Rectangle : public Shape 
{
public:
	Rectangle() : width{ 2 }, height{ 3 }{ }
	Rectangle(const uint16_t newWidth, const uint16_t newHeight) {
		width = newWidth;
		height = newHeight;
	}
	virtual void show() override {
		Shape::show();
		std::cout << "--------show Rectangle---------" << std::endl;
	}
	virtual void hide() override {
		Shape::hide();
		std::cout << "--------hide Rectangle---------" << std::endl;
	}
	virtual void setWidth(const uint16_t newWidth) {
		width = newWidth;
	}
	virtual void setHeight(const uint16_t newHeight) {
		height = newHeight;
	}
	void setEdges(const uint16_t newWidth, const uint16_t newHeight) {
		width = newWidth;
		height = newHeight;
	}
	uint64_t getArea() const {
		return static_cast<uint64_t>(width) * height;
	}
private:
	uint16_t width;
	uint16_t height;
};

class Circle : public Shape
{
public:
	void show() override {
		std::cout << "--------show Circle---------" << std::endl;
	}
	void hide() override{
		std::cout << "--------hide Circle---------" << std::endl;
	}
private:
	uint16_t redius;
};

class TextLabel : public Shape
{
public:
	void show() override {
		std::cout << "--------show TextLabel---------" << std::endl;
	}
	void hide() override {
		std::cout << "--------hide TextLabel---------" << std::endl;
	}
	void setText(std::string newText) {
		text = newText;
	}
private:
	std::string text;
};

using ShapePtr = std::shared_ptr<Shape>;
using shapeCollection = std::vector<ShapePtr>;

void showAllShape(const shapeCollection& shapes)
{
	for (auto& t : shapes)
	{
		t->show();
	}
}

int main()
{
	shapeCollection shapes;
	shapes.push_back(std::make_shared<Rectangle>());
	shapes.push_back(std::make_shared<Circle>());
	shapes.push_back(std::make_shared<TextLabel>());
	showAllShape(shapes);

	system("pause");
	return 0;
}

运行结果如下:

 3.2、需求2

在上述设计中,新增正方形。

方案1

从Rectangle派生一个新类Squre。

UML类如下:

但是方案1不是一个好的解决方案,Square提供一个带有两个参数的接口setEdges(违反了最少惊讶原则)会令人非常费解。如果使用两个相同的值,setWidth和setHeight接口将无法进行赋值。

方案2

从需求分析,正方形并不是矩形的子类型,因此使用组合而不是继承。为了不违反DRY原则,使用Rectangle类的实例作为Square的内部实现。

UML类图如下:

 代码实现:

class Square : public Shape
{
public:
	Square() {
		impl.setEdges(5, 5);
	}
	explicit Square(const uint16_t edgeLength) {
		impl.setEdges(edgeLength, edgeLength);
	}
	void setEdge(const uint16_t length) {
		impl.setEdges(length, length);
	}
	virtual void moveTo(const Point& newCenterPoint) override {
		impl.moveTo(newCenterPoint);
	}
	virtual void show() override {
		impl.show();
	}
	virtual void hide() override {
		impl.hide();
	}
	uint64_t getArea() const {
		return impl.getArea();
	}
private:
	Rectangle impl;
};

四、接口隔离原则

1、定义

接口隔离原则ISP(Interface Segregation Principle):

> 不应该强迫客户程序依赖它们不用的方法。

> 接口应该小而完备。

五、依赖倒置原则

1、定义

依赖倒置原则DIP(Dependence Inversion Principle):

> 高层模块(稳定)不应该依赖于低层模块(变化),二者都不应该依赖于抽象(稳定)。

> 抽象(稳定)不应该依赖于实现细节(变化),实现细节应该依赖于抽象(稳定)。

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

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

相关文章

JavaScript HTML DOM 改变 HTML

文章目录JavaScript HTML DOM 改变 HTML改变 HTML 输出流改变 HTML 内容改变 HTML 属性JavaScript HTML DOM 改变 HTML HTML DOM 允许 JavaScript 改变 HTML 元素的内容。 改变 HTML 输出流 JavaScript 能够创建动态的 HTML 内容&#xff1a; 今天的日期是&#xff1a; Thu …

JDBC-API详解、SQL注入演示、连接池

文章目录JDBC1&#xff0c;JDBC概述1.1 JDBC概念1.2 JDBC本质1.3 JDBC好处2&#xff0c;JDBC快速入门2.1 编写代码步骤2.2 具体操作3&#xff0c;JDBC API详解3.1 DriverManager3.2 Connection &#xff08;事务归我管&#xff09;3.2.1 获取执行对象3.2.2 事务管理3.3 Stateme…

SQL语句 -非空约束 - 唯一约束 - 主键约束 - 默认约束 -外键约束

文章目录约束约束介绍和分类非空约束唯一约束主键约束默认约束案例练习外键约束约束 约束介绍和分类 约束的概念: 约束是作用于表中列上的规则&#xff0c;用于限制加入表的数据 约束的存在保证了数据库中数据的正确性、有效性和完整性 约束的分类如下: 约束名称描述关键字非…

代码随想录【Day25】| 216. 组合总和 III、17. 电话号码的字母组合

216. 组合总和 III 题目链接 题目描述&#xff1a; 找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数&#xff0c;并且每种组合中不存在重复的数字。 说明&#xff1a; 所有数字都是正整数。 解集不能包含重复的组合。 示例 1: 输入: k 3, n 7 输…

从中国文化看面试挑人标准

文章目录标准一、面相1. 1 四白眼1.2 浓眉二、讲话2.1 言多与气虚总结本文结合中国面相&#xff0c;是个概率性问题&#xff0c;对于个体无效。 标准 正直&#xff0c;三观正&#xff0c;沟通好&#xff0c;技术。从概率上讲&#xff1a; 正直且三观正的人----有恒心&#x…

Python带你制作一个属于自己的多功能音乐播放器

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 就是用Python做一个简易的音乐播放器&#xff0c;废话不多说&#xff0c;咱们直接开干 当然&#xff0c;今天做这个肯定不是最简单的&#xff0c;最简单的音乐播放器&#xff0c;9行代码足以 完整源码等直接在文末名片领…

剑指 Offer 08. 二叉树的下一个结点

摘要 二叉树的下一个结点_牛客题霸_牛客网 给定一个二叉树其中的一个结点&#xff0c;请找出中序遍历顺序的下一个结点并且返回。注意&#xff0c;树中的结点不仅包含左右子结点&#xff0c;同时包含指向父结点的next指针。下图为一棵有9个节点的二叉树。树中从父节点指向子节…

【SpringBoot】简单的文件上传和文件下载以及图片回显

前言 小编我将用CSDN记录软件开发求学之路上亲身所得与所学的心得与知识&#xff0c;有兴趣的小伙伴可以关注一下&#xff01;也许一个人独行&#xff0c;可以走的很快&#xff0c;但是一群人结伴而行&#xff0c;才能走的更远&#xff01;让我们在成长的道路上互相学习&#…

k8s全解

目录说明Kubernetes介绍应用部署方式演变kubernetes简介kubernetes组件kubernetes概念kubernetes集群环境搭建安装方式kubeadm二进制包集群类型安装要求最终目标准备环境环境初始化服务部署kubeadm中的命令(一般用不着)资源管理YAML语言介绍资源管理方式命令式对象管理kubectl命…

【涨薪技术】0到1学会性能测试 —— 参数化关联

前言 上一次推文我们分享了性能测试工作原理、事务、检查点&#xff01;今天给大家带来性能测试参数化&#xff0c;检查点知识&#xff01;后续文章都会系统分享干货&#xff0c;带大家从0到1学会性能测试&#xff0c;另外还有教程等同步资料&#xff0c;文末免费获取~ 01、性…

什么是分布式锁?几种分布式锁分别是怎么实现的?

一、什么是分布式锁&#xff1a; 1、什么是分布式锁&#xff1a; 分布式锁&#xff0c;即分布式系统中的锁。在单体应用中我们通过锁解决的是控制共享资源访问的问题&#xff0c;而分布式锁&#xff0c;就是解决了分布式系统中控制共享资源访问的问题。与单体应用不同的是&am…

python语音识别whisper

一、背景 最近想提取一些视频的字幕&#xff0c;语音文案&#xff0c;研究了一波 二、whisper语音识别 Whisper 是一种通用的语音识别模型。它在不同音频的大型数据集上进行训练&#xff0c;也是一个多任务模型&#xff0c;可以执行多语言语音识别以及语音翻译和语言识别。 …

Chat Support Board WordPress聊天插件 v3.5.8

功能列表 支持和聊天功能 Slack聊天完全同步 - 直接从Slack发送和接收用户信息。 立即工作 - 只需插入短码&#xff0c;即可立即安装和使用。 丰富的信息 - Dialogflow机器人发送丰富的信息。 机器人--集成一个由API.AI驱动的多语言机器人。 电子邮件通知 - 当收到回复时&#…

JUC 之 比较交换 CAS

—— CAS&#xff08;Compare And Swap&#xff09; 没有 CAS 之前&#xff0c;多线程环境下不使用原子类保证线程安全 i&#xff0c;只能通过 synchronized 加锁的方式&#xff0c;高并发多写情况下&#xff0c;性能影响很大&#xff1b;使用 CAS 之后&#xff0c;可以使用原子…

公司对不同职级能力抽象要求的具体化

要先把当前级别要求的能力提升到精通&#xff0c;然后尝试做下一级别的事情。 但可能不确定高一级的能力要求究竟怎样&#xff0c;不同Title&#xff0c;如“工程师”“高级工程师”和“资深工程师”等。但这样 Title 对我们理解不同级别的能力要求&#xff0c;完全无用。“高…

RecycleView详解

listview缓存请看: listview优化和详解RecycleView 和 ListView对比&#xff1a;使用方法上ListView&#xff1a;继承重写 BaseAdapter&#xff0c;自定义 ViewHolder 与 converView优化。RecyclerView: 继承重写 RecyclerView.Adapter 与 RecyclerView.ViewHolder。设置 Layou…

【华为OD机试模拟题】用 C++ 实现 - 英文输入法(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 分积木(2023.Q1) 【华为OD机试模拟题】用 C++ 实现 - 吃火锅(2023.Q1) 【华为OD机试模拟题】用 C++ 实现 - RSA 加密算法(2023.Q1) 【华为OD机试模拟题】用 C++ 实现 - 构成的正方形数量(2023.Q1) 【华为OD机试模拟…

计算机组成原理考研题精选

运算 1 D状态寄存器of,cf,sf,zf看结果&#xff0c;数据总线传输数据&#xff0c;Alu是核心器件&#xff0c;地址寄存器是存储器件 2 (74条消息) 【细碎知识1】浮点数的规格化_SinHao22的博客-CSDN博客_浮点数规格化 (74条消息) IEEE754 浮点数&#xff1a;简读案例秒懂_theR…

数据结构之8种排序算法

文章目录1.插入排序2.希尔排序&#xff1a;3.冒泡排序4.快速排序5.简单选择排序6.堆排序在堆中插入新元素&#xff1a;在堆中删除一个元素&#xff1a;7.归并排序8.基数排序9.外部排序排序算法1.插入排序 每次将一个待排序的记录按其关键字大小插入到前面已经排好序的子序列中…

量子态操作:基于门的三态旋转

R-旋转操作 在量子计算中&#xff0c;RX, RY, RZ门是三种基本的单量子比特旋转门&#xff0c;它们分别绕X轴、Y轴、Z轴旋转量子比特的态矢量。 RX旋转门&#xff1a;绕X轴旋转角度为θ\thetaθ的RX门的矩阵表示为&#xff1a; Rx(θ)(cosθ2−isinθ2−isinθ2cosθ2)R_x(\th…