关于软件设计模式的理解
系列文章
关于时间复杂度o(1), o(n), o(logn), o(nlogn)的理解
关于HashMap的哈希碰撞、拉链法和key的哈希函数设计
关于JVM内存模型和堆内存模型的理解
关于代理模式的理解
关于Mysql基本概念的理解
关于软件设计模式的理解
文章目录
- 前言
- 一、软件设计模式遵循的六大原则
- 二、学习软件设计模式的意义
- 三、使用率最高的设计模式有哪几个?具体使用场景举例
- 1.单例模式(Singleton)
- 2.工厂模式(Factory)
- 3.观察者模式(Observer)
- 4.策略模式(Strategy)
前言
软件设计模式(Software Design Pattern),是一套被反复使用的、关于代码设计经验的总结。被用来解决一些不断重复发生的问题,是前辈们的代码设计经验的总结,具有一定的普遍性,可以反复使用。其目的是为了提高代码的可重用性、代码的可读性和代码的可靠性
一、软件设计模式遵循的六大原则
设计模式通常遵循的六大原则是:
开放封闭原则(Open/Closed Principle,OCP): 软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。这意味着在不修改现有代码逻辑的情况下,能够通过扩展来增加新的功能。
单一职责原则(Single Responsibility Principle,SRP): 一个类应该只负责一种类型的任务或职责。
里氏替换原则(Liskov Substitution Principle,LSP): 子类型必须能够替换掉它们的父类型,而不影响程序的正确性。
依赖倒置原则(Dependency Inversion Principle,DIP): 应该依赖于接口或抽象类,而不是具体的实现。
接口隔离原则(Interface Segregation Principle,ISP): 一个类不应该依赖它不需要的接口。
合成/聚合复用原则(Composition/Aggregation Reuse Principle,CARP): 应该优先使用对象组合或聚合,而不是继承来实现代码复用。
这些原则提供了指导,帮助开发人员设计出灵活、可维护、可扩展和易于理解的软件系统。虽然并不是每种设计模式都严格遵循这些原则,但设计模式通常是以这些原则为基础来提供解决特定问题的通用方案
二、学习软件设计模式的意义
设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充分理解。正确使用设计模式具有以下优势。:
- 可以提高程序员的思维能力、编程能力和设计能力。
- 可以使程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期。
- 可以使设计的代码可复用性高、可读性强、可靠性高、灵活性好、可维护性强。
三、使用率最高的设计模式有哪几个?具体使用场景举例
1.单例模式(Singleton)
场景举例: 当系统中需要确保一个类只有一个实例,并提供全局访问点时,通常使用单例模式。如数据库连接池、日志管理器等
代码案例:
步骤 1: 创建单例类
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;public class DatabaseConnection {// 数据库连接相关配置private static final String URL = "jdbc:mysql://localhost:3306/mydatabase";private static final String USERNAME = "username";private static final String PASSWORD = "password";// 私有静态变量,保存类的唯一实例private static DatabaseConnection instance;// 数据库连接对象private Connection connection;// 私有构造函数,防止外部直接创建对象private DatabaseConnection() {try {// 创建数据库连接connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);} catch (SQLException e) {e.printStackTrace();}}// 公有静态方法,返回唯一实例public static DatabaseConnection getInstance() {if (instance == null) {// 确保线程安全synchronized (DatabaseConnection.class) {if (instance == null) {instance = new DatabaseConnection();}}}return instance;}// 获取数据库连接对象public Connection getConnection() {return connection;}
}
步骤 2: 使用单例类
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class Main {public static void main(String[] args) {// 获取数据库连接Connection connection = DatabaseConnection.getInstance().getConnection();// 执行数据库操作try {PreparedStatement statement = connection.prepareStatement("SELECT * FROM users");ResultSet resultSet = statement.executeQuery();while (resultSet.next()) {System.out.println("User ID: " + resultSet.getInt("id") + ", Name: " + resultSet.getString("name"));}resultSet.close();statement.close();} catch (SQLException e) {e.printStackTrace();}}
}
解释
单例模式的核心: 私有构造函数和一个返回实例的公有静态方法。
线程安全: 使用双重检查锁定确保在多线程环境下安全创建实例。
延迟初始化: 实例在类被加载时不会创建,在首次需要时才创建,节省资源。
数据库连接池: 这种方式也可以用于实现简单的数据库连接池,通过控制并发访问来管理连接数,提高数据库连接的效率和资源利用率。
这种实现方式在实际应用中非常有用,特别是在需要频繁访问数据库的情况下,可以减少连接的开销和管理成本。
2.工厂模式(Factory)
场景举例: 当需要创建多个具有相似功能的对象时,使用工厂模式可以将对象的创建逻辑封装在一个工厂类中,提高代码的灵活性和可维护性。如数据库驱动管理等
代码案例:
步骤 1: 创建接口
import java.sql.Connection;public interface DatabaseConnection {Connection getConnection();
}
步骤 2: 创建具体实现类
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;public class MySQLConnection implements DatabaseConnection {// MySQL数据库连接相关配置private static final String URL = "jdbc:mysql://localhost:3306/mydatabase";private static final String USERNAME = "username";private static final String PASSWORD = "password";@Overridepublic Connection getConnection() {Connection connection = null;try {// 创建MySQL数据库连接connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);} catch (SQLException e) {e.printStackTrace();}return connection;}
}
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;public class PostgreSQLConnection implements DatabaseConnection {// PostgreSQL数据库连接相关配置private static final String URL = "jdbc:postgresql://localhost:5432/mydatabase";private static final String USERNAME = "username";private static final String PASSWORD = "password";@Overridepublic Connection getConnection() {Connection connection = null;try {// 创建PostgreSQL数据库连接connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);} catch (SQLException e) {e.printStackTrace();}return connection;}
}
步骤 3: 创建工厂类
public class ConnectionFactory {public static DatabaseConnection getDatabaseConnection(String dbType) {if (dbType.equalsIgnoreCase("MySQL")) {return new MySQLConnection();} else if (dbType.equalsIgnoreCase("PostgreSQL")) {return new PostgreSQLConnection();}return null;}
}
步骤 4: 使用工厂模式获取数据库连接
import java.sql.Connection;public class Main {public static void main(String[] args) {// 获取MySQL数据库连接DatabaseConnection mysqlConnection = ConnectionFactory.getDatabaseConnection("MySQL");Connection mysqlConn = mysqlConnection.getConnection();// 获取PostgreSQL数据库连接DatabaseConnection postgresConnection = ConnectionFactory.getDatabaseConnection("PostgreSQL");Connection postgresConn = postgresConnection.getConnection();// 使用数据库连接执行操作...}
}
解释
工厂模式的核心: 根据条件动态创建对象,将创建逻辑封装在工厂类中,客户端无需关心具体的创建细节。
可扩展性: 当需要新增其他类型的数据库连接时,只需在工厂类中添加相应的创建逻辑即可,不需要修改客户端代码。
解耦: 客户端与具体数据库连接类之间解耦,通过工厂类进行统一管理,降低了代码的耦合度。
工厂模式能够很好地应对数据库驱动管理场景中的需求变化,使得代码更加灵活和可维护。
3.观察者模式(Observer)
场景举例: 当一个对象的状态发生改变时,需要通知其他相关对象,并自动更新它们的状态时,通常使用观察者模式。如消息订阅与发布系统等
代码案例:
步骤 1: 创建主题接口
首先,定义一个主题接口,用于注册、删除和通知观察者。
public interface Subject {void registerObserver(Observer observer);void removeObserver(Observer observer);void notifyObservers();
}
步骤 2: 创建观察者接口
然后,定义一个观察者接口,用于接收主题的通知。
public interface Observer {void update(String message);
}
步骤 3: 创建具体主题类
接下来,创建具体的主题类,实现主题接口,并维护观察者列表,以及在状态变化时通知观察者。
import java.util.ArrayList;
import java.util.List;public class MessageTopic implements Subject {private List<Observer> observers;private String message;public MessageTopic() {this.observers = new ArrayList<>();}@Overridepublic void registerObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update(message);}}public void setMessage(String message) {this.message = message;notifyObservers();}
}
步骤 4: 创建具体观察者类
然后,创建具体的观察者类,实现观察者接口,并在接收到通知时执行相应的操作。
public class MessageSubscriber implements Observer {private String name;public MessageSubscriber(String name) {this.name = name;}@Overridepublic void update(String message) {System.out.println(name + " received message: " + message);}
}
步骤 5: 使用观察者模式
最后,在应用程序中使用观察者模式。
public class Main {public static void main(String[] args) {// 创建主题MessageTopic topic = new MessageTopic();// 创建观察者Observer subscriber1 = new MessageSubscriber("Subscriber 1");Observer subscriber2 = new MessageSubscriber("Subscriber 2");// 注册观察者topic.registerObserver(subscriber1);topic.registerObserver(subscriber2);// 发布消息topic.setMessage("Hello, world!");}
}
解释
主题接口: 定义了注册、删除和通知观察者的方法。
观察者接口: 定义了观察者需要实现的更新方法。
具体主题类: 实现了主题接口,维护了观察者列表,并在状态变化时通知所有观察者。
具体观察者类: 实现了观察者接口,定义了接收通知时的具体行为。
使用观察者模式: 创建主题对象,创建观察者对象并注册到主题中,然后发布消息。所有注册的观察者都会接收到消息通知并执行相应的操作。
观察者模式非常适用于消息订阅与发布场景,可以实现松耦合的通信机制,让发布者和订阅者之间的关系更加灵活。
4.策略模式(Strategy)
场景举例: 当需要在运行时根据不同的情况选择算法或行为时,使用策略模式可以将不同的算法封装成不同的策略类,使得算法的变化独立于使用算法的客户。如支付系统中的支付策略等
代码案例:
步骤 1: 创建支付策略接口
首先,定义一个支付策略接口,用于定义支付的方法。
public interface PaymentStrategy {void pay(double amount);
}
步骤 2: 创建具体的支付策略类
然后,创建具体的支付策略类,实现支付策略接口,每个具体的支付策略类代表一种支付方式,例如信用卡支付、支付宝支付、微信支付等
public class CreditCardPayment implements PaymentStrategy {private String cardNumber;private String expiryDate;private String cvv;public CreditCardPayment(String cardNumber, String expiryDate, String cvv) {this.cardNumber = cardNumber;this.expiryDate = expiryDate;this.cvv = cvv;}@Overridepublic void pay(double amount) {System.out.println("Paid " + amount + " via credit card.");}
}public class AlipayPayment implements PaymentStrategy {private String account;public AlipayPayment(String account) {this.account = account;}@Overridepublic void pay(double amount) {System.out.println("Paid " + amount + " via Alipay.");}
}public class WechatPayment implements PaymentStrategy {private String account;public WechatPayment(String account) {this.account = account;}@Overridepublic void pay(double amount) {System.out.println("Paid " + amount + " via WeChat.");}
}
步骤 3: 创建上下文类
接下来,创建上下文类,用于持有具体的支付策略对象,并提供支付方法。
public class PaymentContext {private PaymentStrategy paymentStrategy;public PaymentContext(PaymentStrategy paymentStrategy) {this.paymentStrategy = paymentStrategy;}public void setPaymentStrategy(PaymentStrategy paymentStrategy) {this.paymentStrategy = paymentStrategy;}public void pay(double amount) {paymentStrategy.pay(amount);}
}
步骤 4: 使用策略模式
最后,在应用程序中使用策略模式进行支付。
public class Main {public static void main(String[] args) {// 创建支付上下文PaymentContext paymentContext = new PaymentContext(new CreditCardPayment("1234 5678 9012 3456", "12/24", "123"));// 进行支付paymentContext.pay(100.0);// 切换支付方式paymentContext.setPaymentStrategy(new AlipayPayment("example@example.com"));// 进行支付paymentContext.pay(200.0);}
}
解释
支付策略接口: 定义了支付的方法。
具体的支付策略类: 实现了支付策略接口,每个类代表一种支付方式,实现了具体的支付逻辑。
支付上下文类: 持有具体的支付策略对象,并提供支付方法,客户端通过上下文类进行支付。
使用策略模式: 创建支付上下文对象,根据需要设置不同的支付策略,然后进行支付操作。
策略模式能够有效地解耦客户端和具体的支付策略,使得支付系统更加灵活,易于扩展和维护。
相关文章:
关于软件设计模式的理解
系列文章 关于时间复杂度o(1), o(n), o(logn), o(nlogn)的理解 关于HashMap的哈希碰撞、拉链法和key的哈希函数设计 关于JVM内存模型和堆内存模型的理解 关于代理模式的理解 关于Mysql基本概念的理解 关于软件设计模式的理解 文章目录 前言一、软件设计模式遵循的六大原则…...
Java开发官方文档
Spring中文网 Spring Cloud中文网 Hutool工具类 Ant Design官方文档 遇见狂神说学习文档 若依后台管理系统测试环境 FineBI官方文档 vscode教程 新一代微服务全家桶AlibabaCloudSpringCloud实战 分布式任务调度平台XXL-JOB...

AI大模型探索之路-实战篇9:探究Agent智能数据分析平台的架构与功能
系列篇章💥 AI大模型探索之路-实战篇4:深入DB-GPT数据应用开发框架调研 AI大模型探索之路-实战篇5:探索Open Interpreter开放代码解释器调研 AI大模型探索之路-实战篇6:掌握Function Calling的详细流程 AI大模型探索之路-实战篇7…...
本地spark3.5(不整合hive) 集成paimon0.9
spark官网下载集成hadoop的spark包: spark-3.5.1-bin-hadoop3.... 解压后 环境变量配置 SPARK_HOME spark-defaults.conf 中增加一行配置(避免启动spark-sql报错hive元数据连不上): spark.sql.catalogImplementationhive 打开paimon官网: https://paimon.apache.org/docs/mas…...

Linux IO模型深度解析与实战应用
linux的5种IO模型 一、这里IO是什么 操作系统设有用户态与内核态,确保系统安全。应用程序默认在用户态运行,而执行如IO操作等底层任务时,需切换至内核态以高效执行。 服务器从网络接收的大致流程如下: 1、数据通过计算机网络来到了网卡 2、把网卡的数据读取到 socket 缓…...

软件系统开发标准流程文档(Word原件)
目的:规范系统开发流程,提高系统开发效率。 立项申请需求分析方案设计方案评审开发调整测试阶段系统培训试运行测试验收投入使用 所有文档过去进主页获取。 软件项目相关全套精华资料包获取方式①:点我获取 获取方式②:本文末个人…...

嵌入式进阶——外部中断(EXTI)
🎬 秋野酱:《个人主页》 🔥 个人专栏:《Java专栏》《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 STC8H中断外部中断外部中断编写配置外部中断调用中断触发函数 外部中断测试测试外部中断0测试外部中断2、3或者4 PCB中断设计 STC8…...

flinkcdc 3.0 源码学习之客户端flink-cdc-cli模块
注意 : 本文章是基于flinkcdc 3.0 版本写的 我们在前面的文章已经提到过,flinkcdc3.0版本分为4层,API接口层,Connect链接层,Composer同步任务构建层,Runtime运行时层,这篇文章会对API接口层进行一个探索.探索一下flink-cdc-cli模块,看看是如何将一个yaml配置文件转换成一个任务…...

香橙派 AIpro开发体验:使用YOLOV8对USB摄像头画面进行目标检测
香橙派 AIpro开发体验:使用YOLOV8对USB摄像头画面进行目标检测 前言一、香橙派AIpro硬件准备二、连接香橙派AIpro1. 通过网线连接路由器和香橙派AIpro2. 通过wifi连接香橙派AIpro3. 使用vscode 通过ssh连接香橙派AIpro 三、USB摄像头测试1. 配置ipynb远程开发环境1.…...
Python中正则表达式详解
Python中正则表达式详解 引言 正则表达式是一种用于字符串搜索和操作的强大工具。它使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在Python中,正则表达式通过内置的re模块来实现,使得文本处理变得简洁而高效。 正则表达式基础 在深入…...
vue使用EventBus进行跨组件通信
Vue中的EventBus,又称为事件总线,是一种常用的通信模式,它允许在Vue应用程序的不同组件之间进行松耦合的通信,尤其是对于那些没有直接父子关系的组件间的通信非常有用。EventBus基于Vue的自定义事件系统实现,工作原理遵…...

boot项目中定时任务quartz
最近换项目组,发现项目中定时任务使用的是quartz框架,上一篇文章[springboot定时任务]也是使用的quartz,只不过实现方式不同,于是整理下 定时任务常用方法有Quartz,Spring自带的Schedule框架 Quartz基础知识 quartz…...

使用阿里云OSS实现视频上传功能
目录 前言 视频上传 前言 阿里云对象存储服务(OSS)作为一种高可用、高扩展性的云端存储服务,为开发者提供了便捷、安全的对象存储解决方案。本文将介绍如何利用阿里云OSS实现视频上传功能。 视频上传 前期准备请看阿里云OSS文件上传和下载…...

LOTO示波器软件新增导览功能
新版本的大部分型号LOTO示波器的上位机软件我们改成了导航工具条方式。原来的方式是把所有功能都显示在不同的标签页中,这样的优点是非常快捷方便,基本上用鼠标一两次点击就能直达想要的功能设置。但是缺点是不熟练的客户可能记不住各种功能的标签位置在…...

【StructueEngineering】SYMBOL SCHEDULE
文章目录 标记表列SYMBOL SCHEDULELINES线条COLUMN REFERENCE SYMBOL柱参考标记SECTION REFERENCE SYMBOLS剖面参考标记DETAILREFERENCE SYMBOLS详图参考标记GENERALELEVATIONSYMBOLS一般立面图标记MISCELLANEOUS SYMBOLS杂项标记 STEEL FRAMING SYMBOLS钢结构平面图标记COLUMN…...

简化跨网文件传输摆渡过程,降低IT人员工作量
在当今数字化时代,IT企业面临着日益增长的数据交换需求。随着网络安全威胁的不断演变,网关隔离成为了保护企业内部网络不受外部威胁的重要手段。然而,隔离的同时,企业也需要在不同网络间安全、高效地传输文件,这就催生…...

关于python中屏蔽输出
python中屏蔽输出包含屏蔽标准输出(比如打印出来的内容)、屏蔽标准错误(错误信息)还有屏蔽logging信息等。 屏蔽标准输出 import contextlib import oswith open(os.devnull, "w") as devnull:with contextlib.redire…...

螺旋矩阵(算法题)
文章目录 螺旋矩阵解题思路 螺旋矩阵 给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 示例 1: 输入:n 3 输出:[[1,2,3],[8,9,4],[7,6,5]]解题思路 模…...

ffmpeg-webrtc(metartc)给ffmpeg添加webrtc协议
这个是使用metrtc的库为ffmpeg添加webrtc传输协议,目前国内还有一个这样的开源项目,是杨成立大佬,大师兄他们在做,不过wili页面维护的不好,新手不知道如何使用,我专门对它做过介绍,另一篇博文&a…...
C语言知识大纲
一、基础 (一)变量定义和使用 (二)数据类型的字节数 (三)变量转换 (四)程序主要结构 (五)if和else判断 (六)switch判断 (七)while循环 (八)do while循环 (九)for循环 (十)基本输入输出 (十一)数组定义和使用 (十二)函数定义和使用 (十三)指针 (十四)多级指针 (十…...

从入门到实战:AI学习路线全解析——避坑指南
分享一下阿里的人工智能学习路线,为感兴趣系统学习的小伙伴们探路。 一、谁适合学这门AI课程?五类人群的精准定位 无论你是零基础小白还是职场转型者,这套系统化课程都能为你量身定制成长路径: 零基础爱好者(无编程/数学背景) 课程提供Python和数学前置学习建议,先补基…...
Redis持久化策略:RDB与AOF详解
目录 1. RDB持久化工作原理触发机制优点缺点配置示例 2. AOF持久化工作原理同步策略重写机制优点缺点配置示例 3. RDB与AOF比较4. 混合持久化(Redis 4.0)5. 选择建议 Redis提供了两种主要的持久化机制来保证数据安全:RDB(Redis Database)和AOF(Append Only File)。本…...

算法专题七:分治
快排 1.颜色分类 题目链接:75. 颜色分类 - 力扣(LeetCode) class Solution {public void swap(int[] nums, int i, int j){int t = nums[i];nums[i] = nums[j];nums[j] = t;}public void sortColors(int[] nums) {int left=-1 ,i=0 ,right=nums.length;while(i<right){i…...

Redis实战-消息队列篇
前言: 讲讲做消息队列遇到的问题。 今日所学: 异步优化消息队列基于stream实现异步下单 1. 异步优化 1.1 需求分析 1.1.1 现有下单流程: 1.查询优惠劵 2.判断是否是秒杀时间,库存是否充足 3.实现一人一单 在这个功能中&…...

【第九篇】 SpringBoot测试补充篇
简介 本文介绍了SpringBoot测试中的五项关键技术:测试类专用属性加载、 测试类专用Bean配置、 表现层测试方法、测试类事务回滚控制、配置文件随机数据设置)。这些技术可以有效隔离测试环境,确保测试数据不影响生产环境,同时提供了…...

国产高云FPGA实现视频采集转UDP以太网输出,FPGA网络摄像头方案,提供2套Gowin工程源码和技术支持
目录 1、前言工程概述免责声明 2、相关方案推荐我已有的所有工程源码总目录----方便你快速找到自己喜欢的项目国产高云FPGA基础教程国产高云FPGA相关方案推荐我这里已有的以太网方案 3、设计思路框架工程设计原理框图输入Sensor之-->OV7725摄像头输入Sensor之-->OV5640摄…...

自动驾驶科普(百度Apollo)学习笔记
1. 写在前面 在过去的几年里,自动驾驶技术取得飞速发展,人类社会正逐渐走向一个新时代,这个时代中,汽车不仅仅是一个交通工具,更是一个智能的、能够感知环境、做出决策并自主导航的机器伙伴。现在正好也从事这块的工作…...

Linux--命令行参数和环境变量
1.命令行参数 Linux 命令行参数基础 1.1参数格式 位置参数:无符号,按顺序传递(如 ls /home/user 中 /home/user 是位置参数) 选项参数: 短选项:以 - 开头,单个字母(如 -l 表示长格…...
Kali Linux 安全工具解析
Kali Linux 安全工具解析 目录 Kali Linux 安全工具解析一、Kali Linux 概述1.1 核心特性1.2 系统要求 二、核心工具分类与实战应用2.1 信息收集工具2.1.1 Nmap2.1.2 Recon-ng2.1.3 theHarvester 2.2 漏洞利用工具2.2.1 Metasploit Framework2.2.2 SQLMap2.2.3 Burp Suite 2.3 …...

day26-计算机网络-4
1. tcp的11种状态 ss -ant -a 表示看所有状态 -n 表示不将ip解析为主机名 -t 表示tcp 1.1. closed状态(客户端、服务端) 客户端发起建立连接前的状态服务端启动服务前的状态 1.2. listen状态(服务端) 服务端软件运行的时候状…...