Java享元模式源码剖析及使用场景

享元模式

  • 一、介绍
  • 二、基本原理
  • 三、企业资源管理系统中使用案例
  • 三、Java 中的字符串常量池使用了享元模式
  • 四、总结优缺点以及使用经验

一、介绍

享元模式是一种结构型设计模式,旨在最大程度地减少内存使用或计算开销。这种模式通过共享对多个类似对象实例所需的状态来实现这一目标。

二、基本原理

在享元模式中,存在两种状态:内部状态和外部状态。

  1. 内部状态:可以被多个对象共享,通常不会改变
  2. 外部状态:取决于对象的上下文,并且不能被共享。如果需要,它们可以被单独存储并传递给享元对象。

典型的享元模式实现包括一个工厂类,用于创建和管理共享的享元对象。当客户端请求一个享元对象时,工厂类会检查是否已经有符合要求的对象存在,如果存在则返回共享对象的引用,否则创建一个新的对象并加入到共享池中。

三、企业资源管理系统中使用案例

需求:开发一个企业资源管理系统,系统需要管理大量的员工信息,包括姓名、部门、职位等。由于公司规模较大,员工信息可能会有很多重复,因此我们希望使用享元模式来共享相同的员工实例,以最大程度地节省内存空间

  1. 员工类
// 定义员工类
public class Employee {private String name;private String department;public Employee(String name, String department) {this.name = name;this.department = department;}public void display() {System.out.println("Name: " + name + ", Department: " + department);}
}
  1. 享元工厂类,EmployeeFactory 充当享元工厂,负责创建和管理员工的共享实例
import java.util.HashMap;
import java.util.Map;// 享元工厂
public class EmployeeFactory {private Map<String, Employee> employees = new HashMap<>();public Employee getEmployee(String name, String department) {String key = name + "-" + department;if (!employees.containsKey(key)) {Employee employee = new Employee(name, department);employees.put(key, employee);}return employees.get(key);}
}
  1. 客户端代码,ERPClient 类作为客户端代码,模拟系统中大量重复的员工信息,并通过享元工厂获取共享的员工对象进行展示。
public class ERPClient {public static void main(String[] args) {EmployeeFactory factory = new EmployeeFactory();// 模拟系统中大量重复的员工信息String[][] data = {{"Alice", "HR"}, {"Bob", "Engineering"}, {"Alice", "HR"}};for (String[] rowData : data) {String name = rowData[0];String department = rowData[1];Employee employee = factory.getEmployee(name, department);employee.display();}}
}

三、Java 中的字符串常量池使用了享元模式

字符串常量池是一个存储字符串字面量的特殊内存区域,它确保相同的字符串字面量只会被存储一次,从而节省内存并提高性能。

由 String 类的静态方法 intern() 来实现。当调用 intern() 方法时,如果字符串常量池中已经包含一个等于此 String 对象的字符串(用 equals 方法确定),则返回常量池中这个字符串的引用;否则,将此 String 对象添加到常量池,并且返回此 String 对象的引用。

public class StringConstantPoolExample {public static void main(String[] args) {// 创建字符串对象 "Hello" 并赋值给 s1String s1 = new String("Hello");// 调用 intern() 方法,将字符串放入常量池并返回引用String s2 = s1.intern();// 再次创建字符串对象 "Hello" 并赋值给 s3String s3 = "Hello";// 检查 s2 和 s3 是否引用了相同的对象System.out.println(s2 == s3);  // 输出 true,说明 s2 和 s3 引用的是同一个对象}
}

在 Java 的实现中,intern() 方法是一个 native 方法,它会在底层实现中根据字符串的内容进行查找或插入操作,以保证字符串常量池中的唯一性和共享性

public class String implements java.io.Serializable, Comparable<String>, CharSequence {// ...(其他代码省略)public native String intern();// ...(其他代码省略)
}

四、总结优缺点以及使用经验

  1. 优点:
  • 封装不变部分,扩展可变部分,代码复用性好
  • 父类调用子类操作,通过子类扩展增强功能
  • 符合开闭原则和里氏替换原则
  1. 缺点:
  • 每个不同的实现都需要定义一个子类,类的个数可能过多
  • 父类和子类之间存在潜在的扩展性限制
  • 编写过程复杂,逻辑较难理解
  1. 使用经验:
  • 适用于复杂流程,有固定不变的算法骨架和某些可变的细节
  • 需要先分清楚算法固定部分和可变部分
  • 体现了模板模式的核心思想"继承 + 多态"
  • 在框架设计中是常用的模式,可以提高代码的复用性
  • 不建议过度使用,需要权衡利弊,避免类膨胀
    总之,模板方法模式是一种典型的通过交换算法步骤扩展功能的设计模式,适用于算法骨架固定,某些步骤需要不同实现的场景。恰当使用可以提高代码复用性和系统扩展性

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/736039.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

04 数据结构之队列

循环队列 /* squence_queue.h */ #ifndef _SQUENCE_QUEUE_H_ #define _SQUENCE_QUEUE_H_#include <stdio.h> #include <string.h> #include <stdlib.h>#define QUEUE_SIZE 128 #define DEBUG(msg) \printf("--%s--, %s", __func__, msg)typedef i…

SAP BTP Hyperscaler PostgreSQL都有哪些Performance监控 (一)

前言 SAP BTP云平台中&#xff0c;除了自身的HANA数据库作为首选以外&#xff0c;它还支持PostgreSQL的整套服务&#xff0c;并以PaaS的形式提供给客户。你可以按照实例为单位进行购买申请不同标准规格的PG实例&#xff0c;然后构建自己的业务逻辑。Hyperscaler是这套产品或方…

【Python-Docx库】Word与Python的完美结合

今天给大家分享Python处理Word的第三方库&#xff1a;Python-Docx。 什么是Python-Docx&#xff1f; Python-Docx是用于创建和更新Microsoft Word&#xff08;.docx&#xff09;文件的Python库。 日常需要经常处理Word文档&#xff0c;用Python的免费第三方包&#xff1a;Pyt…

【Linux】Shell及Linux权限

Shell Shell的定义 Shell最简单的定义是&#xff1a;命令行解释器。 Shell的主要任务&#xff1a;1. 将使用者的命令翻译给核心进行处理。2.将核心的处理结果翻译给使用者 为什么要有Shell? 使用者和内核的关系就相当于两个完全陌生的外国人之间的关系&#xff0c;他们要进…

springboot、vue、uniapp项目的部署和运行(超链接可直接跳过去)

springboot、vue项目环境配置 1、首先要安装jdk、maven、mysql、nodejs 软件安装 2、安装idea、HbuilderX、navicat 运行项目 3、运行springboot项目、运行vue项目、运行uniapp项目

Dockerfile编写实践篇

Docker通过一种打包和分发的软件&#xff0c;完成传统容器的封装。这个用来充当容器分发角色的组件被称为镜像。Docker镜像是一个容器中运行程序的所有文件的捆绑快照。当使用Docker分发软件&#xff0c;其实就是分发这些镜像&#xff0c;并在接收的机器上创建容器。镜像在Dock…

Linux:线程互斥与同步

目录 线程互斥 锁的初始化 加锁 解锁 锁的初始化 锁的原理 死锁 线程同步 方案一&#xff1a;条件变量 条件变量初始化 等待 唤醒 条件变量的代码示例 基于阻塞队列的生产消费模型 方案二&#xff1a;POSIX信号量 初始化信号量&#xff1a; 销毁信号量 等待信…

JAVA基础-数据结构一(线性表、链表、栈、队列)

一、数组线性表&#xff08;ADT&#xff09; 线性表&#xff1a;又称动态数组&#xff0c;核心是动态数组&#xff0c;可以自行扩容&#xff0c;支持增删改查四种功能 java中有ArrayList也可以自行扩容&#xff0c;二者功能较为相似&#xff0c;且ArrayList也支持转换为数组。 …

中国大学生计算机设计大赛--智慧物流挑战赛基础

文章目录 一、Ubuntu基础1.1 基本操作1.2 文本编辑 二、ROS基础介绍2.1 概念与特点2.2 基本结构2.3 创建工程2.4 节点和节点管理器2.5 启动文件 三、ROS通信机制3.1 话题3.2 服务3.3 动作3.4 参数服务器 四、ROS可视化工具4.1 rviz4.2 rqt4.3 tf 五、Python实现简单的ROS节点程…

01-分析同步通讯/异步通讯的特点及其应用

同步通讯/异步通讯 微服务间通讯有同步和异步两种方式 同步通讯: 类似打电话场景需要实时响应(时效性强可以立即得到结果方便使用),而且通话期间不能响应其他的电话(不支持多线操作)异步通讯: 类似发邮件场景不需要马上回复并且可以多线操作(适合高并发场景)但是时效性弱响应…

MQ高可用相关设置

文章目录 前言MQ如何保证消息不丢失RabbitMQRocketMQKafkaMQ MQ如何保证顺序消息RabbitMQRocketMQKafka MQ刷盘机制/集群同步RabbitMQRocketMQKafka 广播消息&集群消息RabbitMQRocketMQ MQ集群架构RabbitMQRocketMQKafka 消息重试RabbitMQRockeMqKafka 死信队列RocketMQKaf…

Claude3横空出世:颠覆GPT-4,Anthropic与亚马逊云科技共启AI新时代

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

洛谷P3853路标设置

题目背景 B 市和 T 市之间有一条长长的高速公路&#xff0c;这条公路的某些地方设有路标&#xff0c;但是大家都感觉路标设得太少了&#xff0c;相邻两个路标之间往往隔着相当长的一段距离。为了便于研究这个问题&#xff0c;我们把公路上相邻路标的最大距离定义为该公路的“空…

车载电子电器架构 —— 汽车电子电气系统分解

车载电子电器架构 —— 汽车电子电气系统分解 我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一个人的特殊竞争力&#xff0c;任何…

【JavaWeb】【瑞吉外卖】分页操作数据传输转换

瑞吉day3 搞定了分页以及数据传输的问题 mybatis-plus分页接口实现 分页主要是通过mybatis提供的接口实现的。这篇笔记只是记录如何实现这个接口&#xff0c;并不会深究原理。 博主也比较菜&#xff0c;目前还没有手撕mybatis代码&#xff0c;后续有机会研究一下&#xff08;…

【操作系统概念】第14章:系统保护

文章目录 0. 前言14.1 保护目标14.2 保护原则14.3 保护域14.3.1 域结构14.3.2 实例&#xff1a;UNIX14.3.3 实例&#xff1a;MUTICS 14.4 访问矩阵14.5 访问矩阵的实现14.5.1 全局表14.5.2 对象的访问列表14.5.3 域的能力(权限)列表14.5.4 锁-钥匙机制*14.5.5 比较* 14.6 访问控…

Github 2024-03-10php开源项目日报Top10

根据Github Trendings的统计,今日(2024-03-10统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量PHP项目10Blade项目1Laravel:表达力和优雅的 Web 应用程序框架 创建周期:4631 天开发语言:PHP, BladeStar数量:75969 个Fork数量:24281 次…

网络层学习常见问题及答案整理

问题0&#xff1a;ARP解析协议的定义和特点 ARP&#xff08;地址解析协议&#xff09;高速缓存表用于存储IP地址到MAC地址的映射关系。当一台主机需要将IP数据包发送到同一局域网中的另一台主机时&#xff0c;它需要知道目标主机的MAC地址&#xff0c;以便在以太网帧中使用。AR…

Vue脚手架

Vue脚手架 学习目标&#xff1a; 理解Node.js基本使用方法理解包资源管理器NPM的使用理解webpack的作用理解 vue-cli 脚手架 (重点)Element-UI 组件库 1.vue的格式&#xff1a;new Vue({//作用的视图el:"id选择器",//vue中的数据/*data:{key:value,key:value,...}…

Mysql实现分布式锁

Mysql实现分布式锁 Mysql实现分布式锁 Mysql实现分布式锁 通过数据库的唯一索引和事务的特性来实现分布式锁。 自定义一个表 -- 创建分布式锁表 CREATE TABLE DistributedLock(lock_key VARCHAR(64) NOT NULL,lock_value VARCHAR(255),PRIMARY KEY (lock_key) );-- 尝试获取…