程序猿成长之路之设计模式篇——设计模式简介
无论是对于代码质量还是代码可维护性、可扩展性,使用合适的设计模式都能够起到促进提升的作用,此外在软考的软件工程师、系统架构师职称考试中,设计模式也是必考的一块内容,因此我打算开拓一个新的专栏简单介绍一下设计模式,梳理梳理一些重要的设计模式,帮助各位更好的了解各类型的设计模式以及使用不同类型的设计模式可以带来的好处。
什么是设计模式
如果说代码是一道菜,那么设计模式就如同调料,合理使用可以使代码变得更加得精美;如果说代码是一堆积木,那么设计模式就是搭建积木的手册,合理使用可以使代码变成想要的形状。为了帮助各位了解什么是设计模式,我再举一个例子:
假设现在有1和2两个数字,在不添加其他条件和环境的情况下这两个数字毫无相关性,但是现在有了运算符,有了数学公式,就可以将这两个数字联系起来了,就比如加法运算,1+2 = 3。其中1、2这两个数字可以理解成两个代码片段,而将两个数字相关联的公式可以理解成设计模式,通过设计模式可以将原本看上去不相关的代码片段联系起来,并产生我们想要的结果。
设计模式的好处
- 设计模式可以提高代码的可维护性及可扩展性,符合开闭原则(对扩展开放,对修改关闭)。举个例子,我们已经设计开发了一个类,并且该类符合单一职责原则(一个类仅仅满足实现一个特定的功能)就比如说要进行员工行为明细的录入,我们想在尽可能减少代码改动量和不改动原代码的前提下进行功能上的扩展,比如在录入之后还要对针对员工进行消息推送。这时候我们就可以使用适配器、装饰器或者代理设计模式。这样做的好处就是可以在不改动原来代码的基础上实现功能上的扩展。
- 设计模式可以保证数据的一致性。比如在项目范围内获取一个容器对象,并且要保证获取的容器对象是唯一的,这时候就可以使用单例设计模式。
- 设计模式可以减少代码的修改量,比如我们使用组合策略,可以在只改动组合类的代码就可以实现代码的调整。
- 设计模式可以优化代码结构。
设计模式有哪些分类
- 创建型设计模式:提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用new 直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。常见的创建型设计模式有:工厂模式、抽象工厂模式、单例模式、建造者模式、原型模式、静态工厂模式。
- 结构型设计模式:这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。常见的结构型设计模式有:装饰器、适配器设计模式、外观设计模式、组合设计模式。
- 行为型设计模式:关注行为本身的设计模式,比如关注观察者及被观察者通信的观察者设计模式,关注迭代器间调用的迭代器模式、关注不同行为响应策略的策略模式等。
用一个图片来整体描述一下设计模式之间的关系:
几类设计模式简介
-
创建型设计模式
抽象工厂设计模式:不同工厂类中有不同的产品,但是产品类型是一致的,就比如说海尔有海尔工厂,西门子有西门子工厂,但是无论是海尔还是西门子都生产冰箱等家电产品。如下图所示,ProductA和ProductB都是抽象出来的产品类型,如冰箱和洗衣机,而ConcreteFactory1就可以是海尔集团,ConcreteFactory2就可以是西门子集团,那么ConcreteProductA1就是海尔生产的冰箱而ConcreteProductA2就是西门生产的冰箱,以此类推。
-
结构型设计模式
装饰器设计模式
通过层层嵌套实现完整功能。采用了组合优于继承的策略。
举例:java中的io代码,
InputStream in = new FileInputStream("/test.txt");
InputStream bin = new BufferedInputStream(in);
byte[] data = new byte[128];
while(bin.read(data) != -1) {//...
}
其中in嵌套到BufferedInputStream中就用到了装饰器的嵌套,都是基于InputStream的实现类。
其他示例代码:
package decorator;
/*** 基础接口* @author zygswo**/
public interface BasePrinter {/*** 打印信息* @param msg*/void print();
}package decorator;/*** child接口* @author zygswo*/
public class ChildPrinter implements BasePrinter{/*** 打印日志*/protected volatile BasePrinter printer;/*** 构造方法* @param printer*/public ChildPrinter(BasePrinter printer) {this.printer = printer;}@Overridepublic void print() {System.out.println("ChildPrinter print start");printer.print();System.out.println("ChildPrinter print end");}
}
package decorator;
/*** parent接口* @author zygswo*/
public class ParentPrinter implements BasePrinter{/*** 打印日志*/protected volatile BasePrinter printer;/*** 构造方法* @param printer*/public ParentPrinter(BasePrinter printer) {this.printer = printer;}@Overridepublic void print() {System.out.println("ParentPrinter print start");printer.print();System.out.println("ParentPrinter print end");}
}package decorator;
/*** 接口传参类* @author zygswo*/
public class Printer implements BasePrinter{private String message;public Printer(String message) {this.message = message;}@Overridepublic void print() {System.out.println(message);}
}package decorator;public class Main {public static void main(String[] args) {BasePrinter myprinter = new Printer("hello world");//装饰器层层嵌套BasePrinter childPrinter = new ChildPrinter(new ParentPrinter(myprinter));childPrinter.print();}
}
- 行为型设计模式
观察者设计模式:通过设置观察者和被观察者,使得当被观察者的状态发生变化后,可以及时通知观察者。
示例代码:
/*** 被观察者* @author zygswo*/
public interface Subject{/*** 绑定观察者*/void registerObserver(Observer observer);/*** 通知观察者*/void notifyObserver(String message);
}/*** 观察者* @author zygswo*/
public interface Observer{/*** 更新观察者状态*/void update(Message message);
}/*** 被观察者* @author zygswo*/
public class ConcreteSubject implements Subject{private List<Observer> observers = new ArrayList<>();@Overridepublic void registerObserver(Observer observer) {this.observers.add(observer);}@Overridepublic void notifyObserver(String message) {for(Observer observer: observers) {observer.update(message); //更新观察者信息}}
}/*** 观察者1* @author zygswo*/
public class ConcreteObserverOne implements Observer{@Overridepublic void update(String message) {System.out.println(message);System.out.println("observer1 is updated");}
}/*** 观察者2* @author zygswo*/
public class ConcreteObserverTwo implements Observer{@Overridepublic void update(String message) {System.out.println(message);System.out.println("observer2 is updated");}
}public class Main {public static void main(String[] args) {Subject subject = new Subject();subject.registerObserver(new ConcreteObserverOne());subject.registerObserver(new ConcreteObserverTwo());subject.notifyObserver("hello world");}
}
相关文章:

程序猿成长之路之设计模式篇——设计模式简介
无论是对于代码质量还是代码可维护性、可扩展性,使用合适的设计模式都能够起到促进提升的作用,此外在软考的软件工程师、系统架构师职称考试中,设计模式也是必考的一块内容,因此我打算开拓一个新的专栏简单介绍一下设计模式&#…...

基于Node2Vec的图嵌入实现过程
目录 一、引言二、Node2Vec(原理)2.1 随机游走(Random Walk)2.2 嵌入学习2.3 Node2Vec 的优势 三、使用 Node2Vec 进行图嵌入(实践)3.1 读取和转换 JSON 文件为 Graph 对象3.2 训练 Node2Vec 模型3.3 二维嵌…...

国庆刷题(day4)
C语言: C:...
如何在 Python 3 中制作一个计算器程序
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 简介 Python 编程语言是处理数字和求解数学表达式的强大工具。这种特性可以用来制作有用的程序。 本教程介绍了如何在 Python 3 中制作…...

搭建shopify本地开发环境
虽然shopify提供了在线编辑器的功能,但是远不及本地编辑器方便高效,这篇文章主要介绍如何在本地搭建shopify开发环境: 1、安装nodejs 18.2 2、安装git 3、安装shopify cli ,使用指令: npm install -g shopify/clilatest 4、安装ruby 5、…...

【在Linux世界中追寻伟大的One Piece】进程信号
目录 1 -> 信号入门 1.1 -> 生活角度的信号 1.2 -> 技术应用角度的信号 1.3 -> 注意 2 -> 信号的概念 2.1 -> 用kill -l命令可以查看系统定义的信号列表 2.2 -> 信号处理常见方式 3 -> 产生信号 3.1 -> Core Dump 3.2 -> 调用系统函数…...

MySQL中NULL值是否会影响索引的使用
MySQL中NULL值是否会影响索引的使用 为何写这一篇文章 🐭🐭在面试的时候被问到NULL值是否会走索引的时候,感到有点不理解,于是事后就有了这篇文章 问题: 为name建立索引,name可以为空select * from user …...
Chrome 浏览器:现代网络浏览的先锋
Chrome 浏览器:现代网络浏览的先锋 Chrome 浏览器,由谷歌公司开发的一款快速、简单且安全的网络浏览器,自2008年发布以来,已经成为全球最受欢迎的浏览器之一。本文将深入探讨 Chrome 浏览器的特点、功能、发展历程以及其对现代网…...

蓝牙定位的MATLAB仿真程序(基于信号强度,平面内的定位,四个蓝牙基站)
这段代码通过RSSI信号强度实现了蓝牙定位,展示了如何使用锚点位置和测量的信号强度来估计未知点的位置。它涵盖了信号衰减模型、距离计算和最小二乘法估计等基本概念。通过图形化输出,用户可以直观地看到真实位置与估计位置的关系。 文章目录 蓝牙定位原理蓝牙定位的原理优缺…...

解决docker一直出现“=> ERROR [internal] load metadata for docker.io/library/xxx“的问题
docker拉取镜像时报错,除标题外,还报如下信息 此时想到是不是拉取超时呢,然后配置了一下docker拉取镜像源 vm /etc/docker/daemon.json { "registry-mirrors": ["https://jq794zz5.mirror.aliyuncs.com"] } # 重新加载配…...
Django学习笔记五:templates使用详解
Django的模板系统是一个强大的工具,用于将动态数据渲染到HTML页面中。以下是Django模板系统的详细用法: 模板的基本概念 Django模板使用一个特殊的语法来插入变量、标签和过滤器。 创建模板 创建模板目录:在你的Django应用中创建一个名为…...

PriorityQueue分析
概述 PriorityQueue,优先级队列,一种特殊的队列,作用是能保证每次取出的元素都是队列中权值最小的(Java的优先队列每次取最小元素,C的优先队列每次取最大元素)。元素大小的评判可以通过元素本身的自然顺序…...
Hive数仓操作(六)
一、 Hive 分区表 Hive 的分区表通过在 HDFS 中以不同的目录存储不同的分区数据,来提高查询性能并减少数据扫描量。分区表可以根据特定的列(如 性别 列的男/女)将数据划分为多个部分,使得查询时只需要扫描相关的分区,…...
centos7安装配置python3环境
1、wget https://www.python.org/ftp/python/3.11.2/Python-3.11.2.tgz 2、安装python依赖环境 切换到root用户,然后执行下面命令: 3、安装gcc,用于后续安装Python时编译源码: yum install gcc -y 4、安装Python3相关依赖&#…...

用 LoRA 微调 Stable Diffusion:拆开炼丹炉,动手实现你的第一次 AI 绘画
总得拆开炼丹炉看看是什么样的。这篇文章将带你从代码层面一步步实现 AI 文本生成图像(Text-to-Image)中的 LoRA 微调过程,你将: 了解 Trigger Words(触发词)到底是什么,以及它们如何影响生成结…...

手机实时提取SIM卡打电话的信令声音-(题外、插播一条广告)
手机实时提取SIM卡打电话的信令声音-(题外、插播一条广告) 前言 在去年的差不多这个时候,我们做了一遍外置配件的选型,筛选过滤了一批USB蓝牙配件和type-c转usb的模块。详情可参考《外置配件的电商价格和下载链接的选型.docx》一文:蓝牙电话…...

Linux基于CentOS学习【进程状态】【进程优先级】【调度与切换】【进程挂起】【进程饥饿】
目录 进程状态 状态决定了什么 进程等待方式——队列 进程状态的表现 挂起状态 基于阻塞的挂起——阻塞挂起 swap分区 进程状态表示 Z僵尸状态 进程的优先级 什么是进程的优先级 为什么会有进程的优先级 进程饥饿 Linux的调度与切换 切换 调度 queue [ 140 ]&am…...

Golang | Leetcode Golang题解之第456题132模式
题目: 题解: func find132pattern(nums []int) bool {candidateI, candidateJ : []int{-nums[0]}, []int{-nums[0]}for _, v : range nums[1:] {idxI : sort.SearchInts(candidateI, 1-v)idxJ : sort.SearchInts(candidateJ, -v)if idxI < idxJ {ret…...

回归预测|基于哈里斯鹰优化最小二乘支持向量机的数据回归预测Matlab程序HHO-LSSVM 多特征输入单输出含基础程序
回归预测|基于哈里斯鹰优化最小二乘支持向量机的数据回归预测Matlab程序HHO-LSSVM 多特征输入单输出含基础程序 文章目录 一、基本原理一、基本原理二、HHO-LSSVM的流程三、优缺点四、应用场景 二、实验结果三、核心代码四、代码获取五、总结 一、基本原理 HHO-LSSVM回归预测结…...
【Android 源码分析】Activity生命周期之onStop-1
忽然有一天,我想要做一件事:去代码中去验证那些曾经被“灌输”的理论。 – 服装…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...

html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...

C#中用于控制自定义特性(Attribute)
我们来详细解释一下 [AttributeUsage(AttributeTargets.Class, AllowMultiple false, Inherited false)] 这个 C# 属性。 在 C# 中,Attribute(特性)是一种用于向程序元素(如类、方法、属性等)添加元数据的机制。Attr…...