程序猿成长之路之设计模式篇——设计模式简介
无论是对于代码质量还是代码可维护性、可扩展性,使用合适的设计模式都能够起到促进提升的作用,此外在软考的软件工程师、系统架构师职称考试中,设计模式也是必考的一块内容,因此我打算开拓一个新的专栏简单介绍一下设计模式,梳理梳理一些重要的设计模式,帮助各位更好的了解各类型的设计模式以及使用不同类型的设计模式可以带来的好处。
什么是设计模式
如果说代码是一道菜,那么设计模式就如同调料,合理使用可以使代码变得更加得精美;如果说代码是一堆积木,那么设计模式就是搭建积木的手册,合理使用可以使代码变成想要的形状。为了帮助各位了解什么是设计模式,我再举一个例子:
假设现在有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
忽然有一天,我想要做一件事:去代码中去验证那些曾经被“灌输”的理论。 – 服装…...

【Unity】本地化实现
个人向笔记。 1 前言 记录一下自己的本地化实现思路,暂时只讲本文的本地化实现。 2 文本本地化方案-个人 本地化实现是基于Luban的。自己使用Luban实现了一个“配置表模块”,又实现了一个“全局配置模块”,之后再基于这两个模块实现了“文本…...

Django一分钟:在Django中怎么存储树形结构的数据,DRF校验递归嵌套模型的替代方案
引言 在开发过程中我们可能需要这样的树形结构: [{"data": {"name": "牛奶"},"children": [{"data": {"name": "蒙牛"}, },{"data": {"name": "伊利"}, }]},{"da…...

【Docker从入门到进阶】06.常见问题与解决方案 07.总结与资源
6. 常见问题与解决方案 在使用Docker进行开发和部署过程中,可能会遇到各种问题。以下是一些常见问题及其解决方案: 容器启动失败和调试 在使用 Docker 时,容器启动失败或立即退出可能会导致一定的困扰,以下是进一步深入解决该问…...

快速排序的非递归实现:借助栈实现、借助队列实现
目录 用栈实现快速排序 1.用栈实现非递归快速排序的思路步骤 1.1.思路步骤 2.用栈实现非递归快速排序的代码 3.用栈实现非递归快速排序的整个工程 3.1.QuickSortNonR.h 3.2.QuickSortNonR.c 3.3.Stack.h 3.4.Stack.c 用队列实现非递归快速排序 1.用队列实现非递归快…...

Finops成本优化企业实践-可视化篇
引言:上一章讨论了finops的一些方法论,笔者在拿到finops官方认证finops-engineer certificate之后,将方法论运用到所在项目组中,并于今年完成了40%的费用节省。在此将这些实践方法总结沉淀,与大家分享。实践包括三篇&a…...

Spring Boot中线程池使用
说明:在一些场景,如导入数据,批量插入数据库,使用常规方法,需要等待较长时间,而使用线程池可以提高效率。本文介绍如何在Spring Boot中使用线程池来批量插入数据。 搭建环境 首先,创建一个Spr…...

Python机器学习:自然语言处理、计算机视觉与强化学习
📘 Python机器学习:自然语言处理、计算机视觉与强化学习 目录 ✨ 自然语言处理(NLP) 文本预处理:分词、去停用词词向量与文本分类:使用Word2Vec与BERT 🌆 计算机视觉基础 图像预处理与增强目标…...

Vue2 + ElementUI + axios + VueRouter入门
之前没有pc端开发基础,工作需要使用若依框架进行了一年的前端开发.最近看到一个视频框架一步步集成,感觉颇受启发,在此记录一下学习心得。视频链接:vue2element ui 快速入门 环境搭建和依赖安装 安装nodejs安装Vue Cli使用vue create proje…...

GO网络编程(四):海量用户通信系统2:登录功能核心【重难点】
目录 一、C/S详细通信流程图二、消息类型定义与json标签1. 消息类型定义2. JSON标签3.结构体示例及其 JSON 表示:4.完整代码与使用说明 三、客户端发送消息1. 连接到服务器2. 准备发送消息3. 创建 LoginMes 并序列化4. 将序列化后的数据嵌入消息结构5. 序列化整个 M…...

某项目实战分析代码二
某项目实战分析代码二 此次分析的是protobuf的使用操作流程具体实现 3. 业务数据分析3.1 客户端3.2 服务器端简单案例 此次分析的是protobuf的使用 Protocol Buffer( 简称 Protobuf) 是Google公司内部的混合语言数据标准,它是一种轻便高效的结构化数据存储格式&…...