关于软件设计模式的理解

系列文章
关于时间复杂度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. 可以提高程序员的思维能力、编程能力和设计能力。
  2. 可以使程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期。
  3. 可以使设计的代码可复用性高、可读性强、可靠性高、灵活性好、可维护性强。

三、使用率最高的设计模式有哪几个?具体使用场景举例

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);}
}

解释
支付策略接口: 定义了支付的方法。
具体的支付策略类: 实现了支付策略接口,每个类代表一种支付方式,实现了具体的支付逻辑。
支付上下文类: 持有具体的支付策略对象,并提供支付方法,客户端通过上下文类进行支付。
使用策略模式: 创建支付上下文对象,根据需要设置不同的支付策略,然后进行支付操作。
策略模式能够有效地解耦客户端和具体的支付策略,使得支付系统更加灵活,易于扩展和维护。

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

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

相关文章

前端面试题日常练-day35 【面试题】

题目 希望这些选择题能够帮助您进行前端面试的准备&#xff0c;答案在文末。 1. 以下哪个是使用jQuery选择所有具有CSS类名"myClass"的元素的正确语法&#xff1f; a) $(".myClass") b) $("myClass") c) $("#myClass") d) $("…

FURNet问题

1. 为什么选择使用弱监督学习&#xff1f; 弱监督学习减少了对精确标注数据的依赖&#xff0c;这在医学图像处理中尤为重要&#xff0c;因为高质量标注数据通常需要大量专业知识和时间。弱监督学习通过利用少量标注数据或粗略标注数据来训练模型&#xff0c;降低了数据准备的成…

元组推导式

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 使用元组推导式可以快速生成一个元组&#xff0c;它的表现形式和列表推导式类似&#xff0c;只是将列表推导式中的“[]”修改为“()”。例如&#xf…

python深入解析字符串操作的八大神技

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、字符串的长度与切片 示例代码 二、去除多余的空格 示例代码 三、字符串的开头与包含…

元组的创建和删除

目录 使用赋值运算符直接创建元组 创建空元组 创建数值元组 删除元组 自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 元组&#xff08;tuple&#xff09;是Python中另一个重要的序列结构&#…

JavaScript 获取 HTML 中特定父元素下的子元素

JavaScript 获取 HTML 中特定父元素下的子元素 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <title>查找子元素示例</title> </head> <body><div id"parent"><p&…

CTF-web-攻防世界-2

1、newscenter (1)、访问网站&#xff0c;一个搜索栏&#xff0c;像是SQL注入漏洞&#xff0c;brup抓包尝试一下。 输入2/0、一个单引号、两个单引号、一个双引号、两个双引号等。发现只有一个单引号时&#xff0c;响应包content-length字段有非常明显的变化为0。说明有可能是…

关于堆排序

今天我们不刷力扣了&#xff0c;我们来复习&#xff08;手撕&#xff09;一下数据结构中的八大排序算法之一&#xff0c;堆排序 基本概念&#xff1a; 堆是一种特殊的树形数据结构&#xff0c;即完全二叉树。 堆分为大顶堆和小顶堆&#xff1a; 大顶堆&#xff1a;每个节点的值…

OrangePi KunPengPro | 开发板开箱测评之学习与使用

OrangePi KunPengPro | 开发板开箱测评之学习与使用 时间&#xff1a;2024年5月23日20:51:12 文章目录 OrangePi KunPengPro | 开发板开箱测评之学习与使用概述1.参考2.资料、工具3.使用3-1.通过串口登录系统3-2.通过SSH登录系统3-3.安装交叉编译工具链3-4.复制文件到设备3-5.第…

【组合数学】常考试题答案

一、单项选择题&#xff08;每小题3分&#xff0c;共15分&#xff09; 1. 用3个“1”和4个“0”能组成&#xff08; &#xff09;个不同的二进制数字。 A. 35 B. 36, C. 37, D. 38 2. 整除300的正整数的个数为&#xff08;  &#xff09;。 A. 14…

Anaconda+CUDA+CUDNN+Pycharm+Pytorch安装教程(第一节 Anconda安装)

1.选择和对应的anconda版本 官网地址&#xff1a;Index of / (anaconda.com) 下载地址&#xff1a;Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 2.安装流程 (1)下载安装包 (2)点击next &#xff08;3&#xff09;点击I agree &a…

解决Flutter位于悬浮窗口时,应用Logo不更新问题

问题描述 我已经更换了应用Logo&#xff0c;但是发现应用处于悬浮窗口时&#xff0c;logo还是更改之前的&#xff1f;下面的图片只是示意。 解决方案 终端命令 rm -rf ~/Library/Developer/Xcode/DerivedData2.xcode视图内解决 先在顶部找到 Xcode --> Setting --> Lo…

操作系统入门系列-MIT6.828(操作系统工程)学习笔记(二)----课程实验环境搭建(wsl2+ubuntu+quem+xv6)

MIT6.S081&#xff08;操作系统&#xff09;学习笔记 操作系统入门系列-MIT6.828&#xff08;操作系统&#xff09;学习笔记&#xff08;一&#xff09;---- 操作系统介绍与接口示例 操作系统入门系列-MIT6.828&#xff08;操作系统工程&#xff09;学习笔记&#xff08;二&am…

Java面向对象-常用类(日期时间类)

常用类-日期时间类 Date&#xff08;java.util.Date&#xff09; – 日期类 SimpleDateFormat – 格式化日期类 Calendar – 日历类 1 Date类 java.util.Date类表示特定的瞬间&#xff0c;精确到毫秒。 package com.qf.datetime;import java.util.Date;public class Test01 {…

ubantu20.04 跑通ros2版的orbslam2

我的历程 先编译的非ros版的robslam2&#xff08;非常详细&#xff09; ubuntu20.04配置并编译ORB-SLAM2_ubuntu20.04安装orb-lslam2-CSDN博客 然后装ros2&#xff08;非常详细&#xff09; 详细介绍如何在ubuntu20.04中安装ROS系统&#xff0c;超快完成安装&#xff08;最…

C#解析xml文件

1、示例 <?xml version"1.0" encoding"utf-8" standalone"no"?><DATA><ITEMS><ITEM><ID>01<ID/><CODE>0001<CODE><NAME>测试1<NAME/></ITEM><ITEM><ID>02<…

福昕PDF编辑器自定义快捷方式

你是否为用不惯福昕PDF编辑器自带的快捷键而发愁&#xff1f;今天&#xff0c;我和大家分享一下如何设置自己想要的快捷键方式&#xff0c;希望能对大家有帮助。 步骤一&#xff1a;打开福昕PDF编辑&#xff0c;并找到更多命令 步骤二&#xff1a;切换到键盘一栏&#xff0c;并…

分布式专题

一&#xff1a;分布式事务 1、理论基础 分布式事务主要区分本地事务 什么是本地事务&#xff08;Local Transaction&#xff09;&#xff1f;本地事务也称为数据库事务或传统事务&#xff08;相对于分布式事务而言&#xff09;。尤其对于数据库而言&#xff0c;为了数据安全…

Android 多张图片合成GIF

直接用哔哩哔哩弄的一个库&#xff0c;传送门&#xff1a;https://github.com/bilibili/BurstLinker 他那个库的文档写的比较简陋&#xff0c;所以我决定&#xff0c;我也写得十分简陋 引用&#xff1a; api com.bilibili:burst-linker:0.0.13 使用&#xff1a; /*** param i…

Docker快速搭建Oracle服务

服务器&#xff1a;CentOS7.9 1.安装docker yum install -y docker 2. 设置镜像加速 修改 /etc/docker/daemon.json 文件并添加上 registry-mirrors 键值 阿里云的docker镜像需要自己注册账号&#xff0c;也可以不注册账号&#xff0c;直接使用下面的连接。 也可以写入多…