软件设计模式(二):工厂、门面、调停者和装饰器模式
前言
在这篇文章中,荔枝将会梳理软件设计模式中的四种:工厂模式、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中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
MySQL 主从同步异常处理
阅读原文:https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主,遇到的这个错误: Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一,通常表示ÿ…...
抽象类和接口(全)
一、抽象类 1.概念:如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象,这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法,包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中,⼀个类如果被 abs…...
