【设计模式】结构型设计模式总结之代理模式、装饰模式、外观模式、享元模式
文章目录
- 代理模式
- 示例
- 结构
- 分类
- 动态代理
- 装饰模式
- 示例
- 结构
- 使用场景
- 与代理模式区别
- Context
- 外观模式
- 结构
- 示例
- 使用场景
- Context
- 享元模式
- 结构
- 示例
- 使用场景
- Message
代理模式
代理模式(Proxy Pattern) 是一种结构型设计模式,它提供了一个代理对象,控制对目标对象的访问。代理对象通常在客户端与目标对象之间起到中介的作用,用于扩展目标对象的功能。
定义:为其他对象提供一种代理以控制对这个对象的访问
示例
定义接口
// 公共接口
public interface IShop {void buy();
}
实现真实类
// 真实对象
public class Buyer implements IShop{@Overridepublic void buy() {System.out.println("购买");}
}
定义代理类
// 代理类
public class Buying implements IShop{private IShop iShop;public Buying(IShop iShop) {this.iShop = iShop;}@Overridepublic void buy() {iShop.buy();}
}
测试代码
public class Client {public static void main(String[] args) {// 创建真实对象IShop person1 = new Buyer();// 创建代理对象IShop proxy = new Buying(person1);// 使用代理对象proxy.buy();}
}
结构
Subject(抽象主题):定义目标对象和代理对象的公共接口。
RealSubject(真实主题):实现了Subject接口,定义了具体的业务逻辑。
Proxy(代理):代理对象,包含对真实主题的引用,并且可以在对真实主题的调用前后添加额外的功能。

分类
- 静态代理
静态代理是指在编译时就已经确定代理类的实现,通常是手动编写代理类。静态代理的关键特点是代理类与目标类之间有一一对应的关系。
- 动态代理
动态代理是在运行时动态生成代理对象,而不是在编译时就明确写好的。Java提供了通过反射机制动态的生成代理对象的机制
动态代理
java提供了java.lang.reflect.InvocationHandler,一个便捷的动态代理接口,实现它要重写其调用方法invoke
// 目标接口
public interface Subject {void request();
}// 目标类
public class RealSubject implements Subject {@Overridepublic void request() {System.out.println("真实主题:处理请求。");}
}// 动态代理的处理器
public class DynamicProxyHandler implements InvocationHandler {private Object target;public DynamicProxyHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("代理:在真实主题处理请求之前。");Object result = method.invoke(target, args); // 调用目标方法System.out.println("代理:在真实主题处理请求之后。");return result;}
}// 测试
public class DynamicProxyDemo {public static void main(String[] args) {// 创建一个真实的目标对象RealSubject realSubject = new RealSubject();// 使用Proxy创建代理对象Subject proxy = (Subject) Proxy.newProxyInstance(// 目标类的类加载器realSubject.getClass().getClassLoader(),// 目标类实现的接口new Class[] {Subject.class}, // 代理的处理器(即动态代理的逻辑)new DynamicProxyHandler(realSubject));// 调用代理对象的方法proxy.request();}
}
装饰模式
定义:
动态地向对象添加额外的职责,而不改变其结构。
使用场景:
需要透明且动态地扩展类的功能时
示例
// 抽象组件类
public abstract class Component {// 抽象操作方法,由子类实现public abstract void operate();
}
// 具体组件类
public class ConcreteComponent extends Component {@Overridepublic void operate() {System.out.println("执行基本操作");}
}
// 装饰者基类
public abstract class Decorator extends Component {protected Component component; // 持有组件对象的引用public Decorator(Component component) {this.component = component;}@Overridepublic void operate() {component.operate(); // 调用组件的操作}
}
// 具体装饰者实现类
public class ConcreteDecoratorA extends Decorator {public LoggingDecorator(Component component) {super(component);}@Overridepublic void operate() {System.out.println("开始");super.operate(); // 调用原始操作System.out.println("结束");}
}
public class DecoratorPatternDemo {public static void main(String[] args) {// 创建具体组件Component component = new ConcreteComponent();// 根据组件对象构造装饰者componentA并调用Component componentA = new ConcreteDecoratorA(component);componentA.operate();}
}

结构
- 抽象组件(Component): 一个接口或抽象类,被装饰的原始对象
- 具体组件(ConcreteComponent): 抽象组件的具体实现,是被装饰的核心对象
- 抽象装饰者(Decorator): 抽象类或接口,持有一个组件对象的引用,并定义与组件一致的接口
- 具体装饰者(ConcreteDecorator): 抽象装饰者实现类,对抽象装饰者做出具体的实现
使用场景
- 动态扩展一个类的功能。
- 替代多层次的继承结构。
- 当不能直接修改类或不希望影响其他对象时。
与代理模式区别
装饰模式:
- 目的:装饰模式用于动态地扩展一个对象的功能,且对客户端透明。它是继承关系的替代方案,可以通过包装原对象并为其添加新的功能,而不改变原对象的结构。
- 使用场景:当你需要扩展对象的功能时,不希望直接修改原有的类时
代理模式:
- 目的:代理模式用于为其他对象提供一个替代品或代理对象,以便通过代理对象来控制对原对象的访问。代理对象本身不增强原对象的功能,而是控制访问、延迟加载、安全检查等。
- 使用场景:当你希望控制对某个对象的访问(例如,延迟加载、访问权限控制、日志记录等)时,可以使用代理模式。
装饰模式强调对对象功能的增强和扩展。
代理模式关注对对象的访问控制、管理、替代。
核心区别:装饰模式是为了增强原对象的功能,而代理模式是为了控制原对象的访问。
Context

// 抽象组件
public abstract class Context {public abstract void startActivity(@RequiresPermission Intent intent);public void startActivity(Intent intent, Bundle options);
}
// 具体组件实现类
class ContextImpl extends Context{@Overridepublic void startActivity(Intent intent) {warnIfCallingFromSystemProcess();startActivity(intent, null);}@Overridepublic void startActivity(Intent intent, Bundle options) {warnIfCallingFromSystemProcess();final int targetSdkVersion = getApplicationInfo().targetSdkVersion;if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0&& (targetSdkVersion < Build.VERSION_CODES.N|| targetSdkVersion >= Build.VERSION_CODES.P)&& (options == null|| ActivityOptions.fromBundle(options).getLaunchTaskId() == -1)) {throw new AndroidRuntimeException("Calling startActivity() from outside of an Activity"+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."+ " Is this really what you want?");}mMainThread.getInstrumentation().execStartActivity(getOuterContext(), mMainThread.getApplicationThread(), null,(Activity) null, intent, -1, options);}
}
// 装饰者,持有ContextImpl的对象
public class ContextWrapper extends Context {Context mBase;@Overridepublic void startActivity(Intent intent) {mBase.startActivity(intent);}@Overridepublic void startActivity(Intent intent, @Nullable Bundle options) {mBase.startActivity(intent, options);}
}
Activity extends ContextThemeWrapper
ContextThemeWrapper extends ContextWrapper
Activity就是具体装饰者
ContextImpl的创建和ContextWrapper对ContextImpl引用在ActivityThread的main函数中进行
外观模式
外观模式(Facade Pattern)是一种结构型设计模式,它为复杂的子系统提供一个简单的接口。
目的是简化系统的使用方式,使得调用者可以通过一个统一的入口来访问系统中的多个子系统,而不需要关心子系统的内部实现细节。
结构
外观模式通常包含以下几个角色:
-
Facade(外观类):提供一个简化的接口,委托请求给子系统。
-
Subsystem(子系统类):各个独立的子系统,完成具体的业务逻辑。

示例
// 外观类:简化多个功能操作的接口
class SmartphoneFacade {private Camera camera = new Camera();private MusicPlayer musicPlayer = new MusicPlayer();public void takePhotoAndPlayMusic() {camera.open();camera.takePhoto();musicPlayer.play();}public void stopMusicAndCloseCamera() {musicPlayer.stop();camera.open(); }
}// 子系统相机
class Camera {public void open() {System.out.println("打开相机");}public void takePhoto() {System.out.println("拍照");}
}
// 子系统音乐播放器类似// 客户端
public class FacadePatternExample {public static void main(String[] args) {SmartphoneFacade smartphone = new SmartphoneFacade();smartphone.takePhotoAndPlayMusic();smartphone.stopMusicAndCloseCamera();}
}
使用手机只需要调用相关方法,而不用去管Camera和MusicPlayer的具体实现
使用场景
- 当系统较为复杂时,使用外观模式可以简化与子系统的交互,提供一个更易于使用的接口。
- 为多个子系统提供一个统一的接口。
- 需要解耦子系统与外部代码的依赖关系。
优点:
- 简化接口:隐藏了系统的复杂性,提供了更简单的接口。
- 降低耦合:客户端与子系统之间的耦合度降低,修改子系统的实现不会影响到客户端。
Context
Context封装了很多重要的操作,如startActivity、sendBroadcast、bindService等。因此,Context对开发者来说是最重要的高层接口。Context只是一个定义了很多接口的抽象类,这些接口的功能实现并不是在Context及其子类中,而是通过其他子系统来完成。
Context只是一个抽象类,它的真正实现在Contextlmpl类中,Contextlmpl就是外观类。
startActivity():startActivity()方法启动一个新的Activity,但实际的启动过程是通过ActivityManagerService来完成的。sendBroadcast():底层的实现则是通过BroadcastManager来处理。bindService():bindService()方法允许应用与服务建立连接,实际操作是通过ServiceManager来管理服务的绑定。
享元模式
享元模式用来尽可能减少内存使用量,它适合用于可能存在大量重复对象的场景,来缓存可共享的对象,达到对象共享、避免创建过多对象的效果,可以提升性能、避免内存移除等。
核心思想是复用已经存在的对象,而不是每次都创建新对象。
享元对象中的部分状态是可以共享,可以共享的状态成为内部状态,内部状态不会随着环境变化;不可共享的状态则称为外部状态,它们会随着环境的改变而改变。
在享元模式中会建立一个对象容器,在经典的享元模式中该容器为一个 Map,它的键是享元对象的内部状态,它的值就是享元对象本身。客户端程序通过这个内部状态从享元工厂中获取享元对象,如果有缓存则使用缓存对象,否则创建一个享元对象并且存入容器中,这样一来就避免了创建过多对象的问题。
结构
- 抽象享元(Flyweight):定义享元对象的基类或接口
- 具体享元(ConcreteFlyweight):实现抽象享元对象
- 享元工厂(FlyweightFactory):用于管理享元对象的创建和共享,确保享元对象的复用。
示例
在火车票预订系统中,有很多用户会购买相同类型、相同时间、相同座位的火车票。每次有用户购买相同的火车票时,我们不需要为每个用户创建一个新的火车票对象,而是可以共享相同的火车票对象。享元模式可以帮助我们避免为每个用户创建重复的对象,从而节省内存。
享元对象(Flyweight)
TrainTicket 类是享元对象,表示火车票的固定信息,例如车次、出发时间、座位类型等。
// 享元类:火车票
public class TrainTicket {private String trainNumber; // 车次private String departureTime; // 出发时间// 构造方法,初始化火车票的固定信息public TrainTicket(String trainNumber, String departureTime) {this.trainNumber = trainNumber;this.departureTime = departureTime;}// 购票public void serve(String passengerName) {System.out.println("乘车人:" + passengerName + " ,车次 " + trainNumber +",发车时间: " + departureTime);}
}
享元工厂(FlyweightFactory)
TrainTicketFactory 类是享元工厂,用于管理和共享火车票对象。
public class TrainTicketFactory {private Map<String, TrainTicket> ticketMap = new HashMap<>();public TrainTicket getTrainTicket(String trainNumber, String departureTime) {String key = trainNumber + departureTime;if (!ticketMap.containsKey(key)) {ticketMap.put(key, new TrainTicket(trainNumber, departureTime));System.out.println("购票成功,乘车人:" + trainNumber + ", 车次: " + departureTime);}return ticketMap.get(key); // 返回共享的火车票对象}
}
客户端
public class TrainStation {public static void main(String[] args) {TrainTicketFactory ticketFactory = new TrainTicketFactory();TrainTicket ticket1 = ticketFactory.getTrainTicket("G101", "10:00");TrainTicket ticket2 = ticketFactory.getTrainTicket("G101", "10:00");TrainTicket ticket3 = ticketFactory.getTrainTicket("D202", "14:00");ticket1.serve("Alice");ticket2.serve("Bob");ticket3.serve("Charlie");}
}
TrainTicket类是享元对象,火车票的固定信息,相同的,可以被多个乘客共享。TrainTicketFactory类是享元工厂,维护了一个火车票对象池,确保每种车次、出发时间和座位类型的火车票只创建一次。如果有相同的请求,返回已有的火车票对象。TrainStation类模拟了多个乘客购买相同车次、相同时间的火车票。由于使用了享元模式,虽然有多个乘客,但共享了相同的火车票对象。
使用场景
- 对象创建代价高,且每个对象的内部状态差别不大。
- 需要优化程序性能,减少内存消耗。

Message
在Handler中,使用对象池来管理 Message 对象,能够有效避免频繁的对象创建,减少内存占用和GC频率。
public final class Message implements Parcelable {Message next;// 同步锁的对象public static final Object sPoolSync = new Object();// 对象池的头部,具体实现是链表private static Message sPool;// 当前池中存储的 Message 对象数量private static int sPoolSize = 0;// 对象池的最大容量private static final int MAX_POOL_SIZE = 50;public static Message obtain() {// 线程安全synchronized (sPoolSync) {if (sPool != null) {// 从池中取出一个 Message 对象Message m = sPool;// 更新池的头部为下一个对象sPool = m.next;// 清空当前 Message 对象的链表连接,避免不必要的引用m.next = null;// 清除消息的标志位,表示该对象已被重用m.flags = 0;// 更新池中存储的对象数量sPoolSize--;return m;}}// 如果池中没有可复用的对象,创建一个新的 Message 对象并返回return new Message();}/*** 回收该 Message 对象,准备将其放入对象池中。* 该方法会检查 Message 是否还在使用中,若仍在使用则抛出异常。*/public void recycle() {if (isInUse()) { if (gCheckRecycle) { throw new IllegalStateException("This message cannot be recycled because it "+ "is still in use.");}return; }recycleUnchecked();}/*** 实际进行回收操作,将该对象状态清空,并加入对象池中以供复用。*/void recycleUnchecked() {// 清除对象的各个字段,确保该对象回收后不再持有任何引用flags = FLAG_IN_USE;what = 0;arg1 = 0;arg2 = 0;obj = null;replyTo = null;sendingUid = UID_NONE;workSourceUid = UID_NONE;when = 0;target = null;callback = null;data = null;synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; }}}
}
Message 类承担了三个职责:
- Flyweight 抽象角色:提供了统一的接口来处理对象的共享和复用。
- ConcreteFlyweight 具体享元角色:实际存储对象的状态并处理业务逻辑。
- FlyweightFactory 工厂角色:管理对象池,复用和回收
Message对象。
参考:
- 《设计模式之禅》
- 《Android进阶之光》
- 《Android源码设计模式解析与实战》
相关文章:
【设计模式】结构型设计模式总结之代理模式、装饰模式、外观模式、享元模式
文章目录 代理模式示例结构分类动态代理 装饰模式示例结构使用场景与代理模式区别Context 外观模式结构示例使用场景Context 享元模式结构示例使用场景Message 代理模式 代理模式(Proxy Pattern) 是一种结构型设计模式,它提供了一个代理对象…...
11进阶篇:专业课论文阅读方向指南(2025版)
文章目录 第一个检索式:图情档核心期刊(北大 + CSSCI)发文情况研究方法类关键词研究主题类关键词论文阅读建议第二个检索式:川大公共管理学院在核心期刊(北大 + CSSCI)的发文情况研究方法类关键词研究主题类关键词特点关键词与2024年972(现815)两道题目的映射情况815信…...
watch里可以写异步吗
在Vue的 watch 中可以写异步,但通常不推荐。 原因 - 可维护性差: watch 的主要用途是响应式地监听数据变化。如果在里面写复杂的异步操作,会让代码逻辑变得难以理解和维护。例如,同时监听多个数据变化并触发不同异步操作时&am…...
基于 Spring Boot + Vue 的宠物领养系统设计与实现
引言 近年来,随着人们生活水平的提高,宠物逐渐成为许多家庭的重要成员。然而,宠物的流浪和弃养问题日益严重,这促使社会对宠物领养的需求不断增长。为解决宠物领养中信息不对称、领养流程复杂等问题,设计并实现一个基…...
leetcode399:除法求值
给你一个变量对数组 equations 和一个实数值数组 values 作为已知条件,其中 equations[i] [Ai, Bi] 和 values[i] 共同表示等式 Ai / Bi values[i] 。每个 Ai 或 Bi 是一个表示单个变量的字符串。 另有一些以数组 queries 表示的问题,其中 queries[j]…...
【10】MySQL中的加密功能:如何使用MD5加密算法进行数据加密
文章目录 1. MySQL加密功能概述2. MD5加密算法3. 在MySQL中使用MD5加密4. 使用更安全的加密方法总结 在现代的数据库应用中,数据的安全性和隐私性变得尤为重要。无论是存储用户的个人信息,还是保护敏感的业务数据,确保这些数据不会被未授权访…...
CSS的2D和3D动画效果
CSS的2D和3D动画效果:网页动态设计的魔法 在现代网页设计中,动画已经成为提升用户体验的重要元素。通过引入动态效果,我们不仅可以使交互更加流畅和直观,还能吸引用户的注意力,增强品牌认知度。CSS提供了强大的工具&a…...
30天学会Go--第9天 GO语言 Mysql 学习与实践
30天学会Go–第9天 GO语言 MySQL学习与实践 文章目录 30天学会Go--第9天 GO语言 MySQL学习与实践前言一、MySQL 基础知识1.1 MySQL 的核心特征1.2 MySQL 的常见使用情景 二、安装 MySQL2.1 Windows 安装2.2 macOS 安装2.3 Linux 安装 三、MySQL 常用命令3.1 数据库操作3.2 表操…...
跟李笑来学美式俚语(Most Common American Idioms): Part 54
Most Common American Idioms: Part 54 前言 本文是学习李笑来的Most Common American Idioms这本书的学习笔记,自用。 Github仓库链接:https://github.com/xiaolai/most-common-american-idioms 使用方法: 直接下载下来(或者clone到本地…...
Angular由一个bug说起之十一:排序之后无法展开 Row
问题现象 在使用 Material Table 时,排序功能触发了一个奇怪的 Bug:表格的 Row 无法展开。最终排查发现,问题的根源在于 trackBy 的错误使用。trackBy 方法接受两个参数:index(数据索引)和 row(…...
使用 Flutter 进行移动应用开发:深入探索
文章目录 前言一、介绍二、安装 Flutter 环境三、Flutter 应用结构与基础组件四、状态管理策略五、高级主题结语 前言 随着移动技术的迅猛发展,跨平台开发的需求日益增长。开发者们一直在寻找一种既能保证应用性能又能减少开发成本和时间的技术方案。Flutter 应运而…...
2024年天津市职业院校技能大赛高职组 “信息安全管理与评估”样题第三阶段
(四)第三阶段竞小组(赛项)目(300分) 第三阶段竞赛内容是:网络安全渗透(夺旗挑战赛CTF) 本模块要求参赛者作为攻击方,运用所学的信息收集、漏洞发现、漏洞利用等渗透测试技…...
docker批量创建cloudstack虚拟主机脚本
批量创建cloudstack脚本 #!/bin/bash # 配置变量 container_prefix"cloudworker-" base_ip"192.168.1." start_ip2 #开始ip start_container2 #上同 end_container4 #结束ip 包括 network_name"my_macvlan_network" image_name"dockedahi:…...
npm发布插件到私有仓库保姆级教程
在开发项目的过程中,我们经常需要安装插件依赖,那么怎么把自己开发的组件封装成一个插件,并发布到npm 插件市场或者上传到私有仓库里面呢?今天总结下自己发布插件到私有仓库的记录: 一、创建组件 执行命令创建一个空…...
WinRAR V7.10纯净体验
前言 很多同学在安装了WinRAR之后,每次用这个软件解压文件时,都会先跳出一个广。这个广就像打开了一个新窗口,很打扰人。从WinRAR的5.40版本开始,哪怕是简体中文版的,都会这样弹广告。不管你有没有注册账号࿰…...
scss文件内引入其他scss文件报错
1、今天在编译一些老项目的时候,老是提示下面信息 2、而且有很多Sass import rules are deprecated and will be removed in Dart Sass 3.0.0.警告 3、用npm view sass versions看,其中sass的最新版本是1.82.0 4、经过测试"sass": "1.75…...
1-12 GD32基于定时器输入捕获
前言: 基于本人对相关知识回顾与思考,仅供学习参考 目录 前言: 1.0 输入捕获 2.0 信号周期 3.0 定时器配置 4.0 定时器配置 5.0 定时器中断 后记: 1.0 输入捕获 2.0 信号周期 获取信号周期的方法,在第一次捕获与…...
前端基础的讲解-JS(22)
什么是JSON? 1.json 是一种轻量级的数据交换格式 简单来说:json 就是一种在各个编程语言中流通的数据格式,负责不同编程语言中的数据传递和交互。 类似于: 国际通用语言 - 英语 中国 56 个民族不同地区的通用语言 - 普通话 …...
Minecraft-Datapack数据包开发3-进度与成就
目录 简介成就与进度根进度叶子进度更多的检测方式 简介 代码已经上传: gitee github 成就与进度 工欲善其事必先利其器,别死记硬背,多使用自动生成网站 进度数据包生成器:https://misode.github.io/advancement/指令生成器&…...
泷羽sec-shell编程(3)
shell(3) 声明! 学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
基于SpringBoot在线拍卖系统的设计和实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...
C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...
