软件设计模式(二):工厂、门面、调停者和装饰器模式
前言
在这篇文章中,荔枝将会梳理软件设计模式中的四种:工厂模式、Facade模式、Mediator模式和装饰器Decorator模式。其中比较重要的就是工厂模式和装饰器模式,工厂模式在开发中使用的频数比较高。希望荔枝的这篇文章能讲清楚哈哈哈哈,希望能帮助到有需要的小伙伴~~~
文章目录
前言
一、工厂模式
1.1 简单工厂
1.2 工厂方法
1.3 抽象工厂
二、调停者模式和门面模式
2.1 门面模式Facade
2.2 调停者模式Mediator
三、装饰器模式Decorator
总结
一、工厂模式
1.1 简单工厂
首先定义一个交通工具的工厂函数接口Moveable。
package com.crj.factorymethod;
/*** 工厂函数接口*/
public interface Moveable {void go();
}
我们要实现某一种方式的交通工具就需要通过将该交通工具类实现该接口并重写go方法。
package com.crj.factorymethod;/*** Car类继承工厂函数接口*/
public class Car implements Moveable {public void go() {System.out.println("Car go wuwuwuwuw....");}
}
通过简单工厂模式来返回实例化后的交通工具对象。
package com.crj.factorymethod;/*** 简单工厂模式* 简单工厂的可扩展性不好*/
public class SimpleVehicleFactory {public Car createCar() {//before processingreturn new Car();}public Broom createBroom() {return new Broom();}
}
1.2 工厂方法
上文中可以看出,简单工厂模式的可扩展性比较差,但我们需要新创建一种交通方式的时候就需要重新在工厂SimpleVehicleFactory定义并写死相应的对象方法,这在后期的时候并不容易维护。那么还可以通过不同交通工具各自有一个工厂,方法类型都是继承自Moveable,返回值也是Moveable类型。
package com.crj.factorymethod;/*** 工厂方法*/
public class CarFactory {public Moveable create() {System.out.println("a car created!");return new Car();}
}
main方法
package com.crj.factorymethod;public class Main {public static void main(String[] args) {Moveable m = new CarFactory().create();m.go();}
}
1.3 抽象工厂
前面我们已经把产品的构建和工厂一一对应了,但是我们操作起产品簇还不是很方便,我们可以通过抽象工厂直接操作创建一整个产品簇。在实现创建产品簇之前,我们需要创建抽象产品类、抽象工厂、具体产品类和具体的工厂。
抽象产品类
首先定义一些抽象产品类,并定义相应的抽象方法。

抽象工厂AbstractFactory
抽象工厂定义抽象的方法用于创建相应的产品簇中的类型产品。
package com.mashibing.dp.abstractfactory;public abstract class AbastractFactory {abstract Food createFood();abstract Vehicle createVehicle();abstract Weapon createWeapon();
}
具体工厂类
具体工厂类继承自抽象工厂类,并重写不同类型的产品创建产品的方法。

具体产品类
具体的产品类继承自抽象产品类

main文件
在main文件中我们通过实例化具体产品类得到对象并调用相应的产品创建方法首先产品簇的创建。可以看到在这段demo中我们即使需要得到不同的产品簇,也仅需要通过实例化不同的工厂类即可。
package com.mashibing.dp.abstractfactory;public class Main {public static void main(String[] args) {AbastractFactory f = new ModernFactory();Vehicle c = f.createVehicle();c.go();Weapon w = f.createWeapon();w.shoot();Food b = f.createFood();b.printName();}
}
具体的逻辑可以看一下这张图,荔枝感觉还是没讲得很清楚,剩下三分自己就得靠大家聪明得脑瓜啦。

二、调停者模式和门面模式
2.1 门面模式Facade
门面模式要求一个系统外部与其内部的通信必须通过一个统一的对象进行,通过一个高层次的接口管理外部通信与内部对象簇之间的通信,简单理解就是一个中介(门面),外部仅需要跟这个中介对接即可,中介再委派客户端发送的请求到相应的子系统中,这也是一种黑箱操作。在该模式下可以同时拥有一个或者多个系统,每个系统是一个类的集合,同时系统对于门面只是当成客户端来处理。
需要注意的是:
-
一个系统可以有多个门面
-
门面不参与系统内的业务逻辑
2.2 调停者模式Mediator
调停者模式相当于一个星型连接,该模式多用于消息中间件如MQ中,对象间只需要跟中间人进行沟通即可,由中间人进行消息的收发和处理,是一种解耦的操作。对于门面模式和调停者模式的区别详情可以下图,二者其实区别并不大并且在某些场景下是可以互换的。

三、装饰器模式Decorator
装饰器(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些功能的模式,它属于对象结构型模式。
优点:
- 装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用
- 通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果
- 装饰器模式完全遵守开闭原则
缺点:装饰器模式会增加许多子类,过度使用会增加程序复杂性。
大致看了一些概念性的东西大机器是不是感觉不是特别具象,下面我们可以通过一个例子来理解一下装饰器模式具体是一个怎样的软件设计模式。
package com.crj.Decorator;public class Decorator {/*** 装饰器模式* 使用实体装饰类装饰* @param args*/public static void main(String[] args) {A a = new A();B b = new B();RedShapeDecorator rda = new RedShapeDecorator(a);rda.draw();BlueShapeDecorator rdb = new BlueShapeDecorator(b);rdb.draw();}
}/*** 接口*/
interface Shape{void draw();
}/*** 接口实现类*/
class A implements Shape{@Overridepublic void draw() {System.out.println("这是A类");}
}
class B implements Shape{@Overridepublic void draw() {System.out.println("这是B类");}
}/*** 抽象装饰类*/
abstract class ShapeDecorator implements Shape{protected Shape decoratedShape;public ShapeDecorator(Shape decoratedShape) {this.decoratedShape = decoratedShape;}@Overridepublic void draw() {decoratedShape.draw();}
}/*** 第一个实体装饰类*/
class RedShapeDecorator extends ShapeDecorator{public RedShapeDecorator(Shape decoratedShape) {super(decoratedShape);}@Overridepublic void draw() {super.draw();setRedShapeDecorator(decoratedShape);}private void setRedShapeDecorator(Shape decoratedShape){System.out.println("Red");}
}
/*** 第二个实体装饰类*/
class BlueShapeDecorator extends ShapeDecorator{public BlueShapeDecorator(Shape decoratedShape) {super(decoratedShape);}@Overridepublic void draw() {super.draw();setRedShapeDecorator(decoratedShape);}private void setRedShapeDecorator(Shape decoratedShape){System.out.println("Blue");}
}
在上面的demo中,我们定义了一个普通接口、两个基本的接口实现类、一个抽象装饰类和两个实体装饰类。接口实现类和抽象装饰类都实现了接口的实现方法并重写接口的方法。实体装饰类继承自抽象装饰类,由于抽象装饰类中含有有参构造方法,因此需要使用super关键字声明继承对象。我们通过往实体装饰类对象中传入一个实体类对象,实现了对对象调用的draw()方法的装饰。

可以看一下这张图,我们可以发现其实在Shape接口上我们定义了一个ShapeDecorator抽象装饰类来装饰,所谓装饰其实也是增加功能。在前面中我们也提及装饰的本质就是使用抽象类继承接口,再使用具体的实现类装饰上功能,这种方式极好的解决了子类爆炸的问题。
总结
到现在荔枝也梳理了几种设计模式了,总结一下自己的学习方法:主要是根据文档和大佬视频资源讲解梳理的,再自己手敲示例实现一遍,收获和体会确实是挺大的。学习设计模式可能会比较枯燥,大家加油,荔枝要继续前行咯~
今朝已然成为过去,明日依然向往未来!我是小荔枝,在技术成长的路上与你相伴,码文不易,麻烦举起小爪爪点个赞吧哈哈哈~~~ 比心心♥~~~
相关文章:
软件设计模式(二):工厂、门面、调停者和装饰器模式
前言 在这篇文章中,荔枝将会梳理软件设计模式中的四种:工厂模式、Facade模式、Mediator模式和装饰器Decorator模式。其中比较重要的就是工厂模式和装饰器模式,工厂模式在开发中使用的频数比较高。希望荔枝的这篇文章能讲清楚哈哈哈哈…...
pdf文件签名的问题解决
今天解决冲突的jar,结果出现下面的问题 java.lang.IllegalAccessError: tried to access method org.bouncycastle.asn1.DERNull.<init>()V from class com.itextpdf.text.pdf.security.PdfPKCS7at com.itextpdf.text.pdf.security.PdfPKCS7.getEncodedPKCS7…...
Node.js安装使用
目录 一、安装 Node.js二、环境变量配置三、npm常用命令 Node.js 是一个强大的运行时环境,它使您能够在服务器端运行 JavaScript 代码。它非常流行,用于构建 Web 应用程序、API 和各种后端服务。 一、安装 Node.js 1、访问 Node.js 官方网站。 在主页上…...
sql:SQL优化知识点记录(七)
(1)索引优化5 (2)索引优化6 (3)索引优化7 查询*, 百分号加右边,否则索引会失效 没建立索引之前都是全表扫描 没建立索引 建立索引: 建立索引 id是主键,他也…...
机器学习:基于梯度下降算法的线性拟合实现和原理解析
机器学习:基于梯度下降算法的线性拟合实现和原理解析 线性拟合梯度下降算法步骤算法实现数据可视化(动态展示)应用示例 当我们需要寻找数据中的趋势、模式或关系时,线性拟合和梯度下降是两个强大的工具。这两个概念在统计学、机器…...
关键点数据增强
1.关键点数据增强 # 关键点数据增强 from PIL import Image, ImageDraw import random import json from pathlib import Path# 创建一个黑色背景图像 width, height 5000, 5000 # 图像宽度和高度 background_color (0, 0, 0) # 黑色填充# 随机分布图像 num_images 1 # …...
最小化安装移动云大云操作系统--BCLinux-for-Euler-22.10-everything-x86_64-230316版
CentOS 结束技术支持,转为RHEL的前置stream版本后,国内开源Linux服务器OS生态转向了开源龙蜥和开源欧拉两大开源社区,对应衍生出了一系列商用Linux服务器系统。BCLinux-for-Euler-22.10是中国移动基于开源欧拉操作系统22.03社区版本深度定制的…...
003传统图机器学习、图特征工程
文章目录 一. 人工特征工程、连接特征二. 在节点层面对连接特征进行特征提取三. 在连接层面对连接特征进行特征提取四. 在全图层面对连接特征进行特征提取 一. 人工特征工程、连接特征 节点、连接、子图、全图都有各自的属性特征, 属性特征一般是多模态的。除属性特…...
Apache Tomcat 漏洞复现
文章目录 Apache Tomcat 漏洞复现1. Tomcat7 弱密码和后端 Getshell 漏洞1.1 漏洞描述1.2 漏洞复现1.3 漏洞利用1.3.1 jsp小马1.3.2 jsp大马 1.4 安全加固 2. Aapache Tomcat AJP任意文件读取/包含漏洞2.1 漏洞描述2.1 漏洞复现2.2 漏洞利用工具2.4 修复建议 3. 通过 PUT 方法的…...
Oracle-常用权限-完整版
-- 创建用户 create user TCK identified by oracle; -- 赋权 grant connect,resource to TCK; -- 删除权限 revoke select any table from TCK -- 删除用户 CASCADE(用户下的数据级联删除) drop user TCK CASCADE -- 查询权限列表 select * from user_role_privs; select * fr…...
jenkins 发布job切换不同的jdk版本/ maven版本
1. 技术要求 因为有个新的项目需要使用jdk17 而旧的项目需要jdk1.8 这就需要jenkins在发布项目的时候可以指定jdk版本 2. 解决 jenkins全局工具配置页面 配置新的jdk 路径 系统管理-> 全局工具配置 如上新增个jdk 名称叫 jdk-17 然后配置jdk-17的根路径即可(这…...
如何在小程序中给会员设置备注
给会员设置备注是一项非常有用的功能,它可以帮助商家更好地管理和了解自己的会员。下面是一个简单的教程,告诉商家如何在小程序中给会员设置备注。 1. 找到指定的会员卡。在管理员后台->会员管理处,找到需要设置备注的会员卡。也支持对会…...
PaddleOCR学习笔记2-初步识别服务
今天初步实现了网页,上传图片,识别显示结果到页面的服务。后续再完善。 采用flask paddleocr bootstrap快速搭建OCR识别服务。 代码结构如下: 模板页面代码文件如下: upload.html : <!DOCTYPE html> <html> <…...
【Opencv】Pyhton 播放上一帧,下一帧,存video,逐帧分析
文章目录 读取具体哪一帧等待按钮写入解码方式与文件格式对应全部代码 读取具体哪一帧 这个方法可以获取某一帧: while True:cap.set(cv2.CAP_PROP_POS_FRAMES, current_frame)ret, frame cap.read()if not ret:break等待按钮 这个方法可以显示当前帧,…...
【关于Java:认识异常】
文章目录 一、1. 异常概念与体系结构1.1 异常的概念1.2 常见的异常1.算数异常2.数组越界异常3.空指针异常 1.3 异常的体系结构1.4 异常的分类1. 编译时异常2. 运行时异常(RuntimeException) 二、 异常的处理方式2.1 防御式编程2.2 EAFP:(异常…...
【C++ • STL • 力扣】详解string相关OJ
文章目录 1、仅仅翻转字母2、字符串中的第一个唯一字符3、字符串里最后一个单词的长度4、验证一个字符串是否是回文5、字符串相加总结 ヾ(๑╹◡╹)ノ" 人总要为过去的懒惰而付出代价 ヾ(๑╹◡╹)ノ" 1、仅仅翻转字母 力扣链接 代码1展示&…...
【Tomcat服务部署及优化】
Tomcat 一、什么是Tomcat?二、Tomcat 核心组件2.1 Tomcat 组件2.3 Container组件的结构2.4 Tomcat 请求过程 三、Tomcat 部署3.1 安装JDK3.2 设置JDK环境变量3.3 安装Tomcat并用supervisor启动解压添加到supervisord服务测试能否通过supervisorctl启动 四、Tomcat的端口和主要…...
C++之红黑树
红黑树 红黑树的概念红黑树的性质红黑树结点的定义红黑树的插入红黑树的验证红黑树与AVL树的比较 红黑树的概念 红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上…...
Go语言网络编程(socket编程)TCP
1、TCP编程 1.1.1 Go语言实现TCP通信 TCP协议 TCP/IP(Transmission Control Protocol/Internet Protocol) 即传输控制协议/网间协议,是一种面向连接(连接导向)的、可靠的、基于字节流的传输层(Transport layer)通信协…...
C语言——局部和全局变量
局部变量 定义在函数内部的变量称为局部变量(Local Variable) 局部变量的作用域(作用范围)仅限于函数内部, 离开该函数后是无效的 离开该函数后,局部变量自动释放 示例代码: #include <stdio.h>// 函数定义 …...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...
多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
Golang——6、指针和结构体
指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
