技术成神之路:设计模式(十四)享元模式

介绍

享元模式(Flyweight Pattern)是一种结构性设计模式,旨在通过共享对象来有效地支持大量细粒度的对象。

1.定义


享元模式通过将对象状态分为内部状态(可以共享)和外部状态(不可共享),来减少内存使用和提高性能。

2. 主要作用


  • 降低内存消耗
  • 提高性能
  • 共享相似对象

3. 解决的问题


当程序中存在大量相似对象时,使用享元模式可以有效减少内存占用,避免重复对象的创建。

4. 模式原理


包含角色:

  1. Flyweight: 抽象享元类,定义了享元对象的接口。
  2. ConcreteFlyweight: 具体享元类,实现了抽象享元类的接口,负责存储内部状态。
  3. FlyweightFactory: 享元工厂类,用于创建和管理享元对象,确保共享。

UML类图:
在这里插入图片描述
示例:
模拟一个图形绘制的场景,其中使用享元模式共享相同的图形对象(如圆):

// 享元接口
interface Shape {void draw(String color);
}// 具体享元类
class Circle implements Shape {private String color;public Circle(String color) {this.color = color;System.out.println("Creating Circle of color: " + color);}@Overridepublic void draw(String color) {System.out.println("Drawing Circle of color: " + color);}
}// 享元工厂类
class ShapeFactory {private static final Map<String, Shape> circleMap = new HashMap<>();public static Shape getCircle(String color) {Circle circle = (Circle) circleMap.get(color);if (circle == null) {circle = new Circle(color);circleMap.put(color, circle);}return circle;}
}// 使用
public class FlyweightPatternDemo {public static void main(String[] args) {ShapeFactory shapeFactory = new ShapeFactory();// 共享相同颜色的圆Shape circle1 = shapeFactory.getCircle("Red");circle1.draw("Red");Shape circle2 = shapeFactory.getCircle("Green");circle2.draw("Green");Shape circle3 = shapeFactory.getCircle("Red");circle3.draw("Red");System.out.println("Total Circles created: " + ShapeFactory.circleMap.size());}
}

打印输出:

Creating Circle of color: Red
Drawing Circle of color: Red
Creating Circle of color: Green
Drawing Circle of color: Green
Drawing Circle of color: Red
Total Circles created: 2

🆗,从这个简单的示例,你会发现享元模式其实很简单,就是共享对象 复用对象,一般开发中并不常用。

在安卓中 HandlerMessage 就使用了享元模式,因为在安卓中 几乎所有事件驱动都是通过Message来进行的,可以说它无处不在,这时候就可以使用享元模式以优化内存使用和提高性能。

下面就以 Message 为例,从源码角度剖析其实现原理!

Message 的池化机制
在 Message 类中,有一个静态的对象池,用于存放可重用的 Message 实例。

    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;//定义池的最大容量。private static boolean gCheckRecycle = true;//一个标志位,用于检查回收的消息是否有效。/*** Return a new Message instance from the global pool. Allows us to* avoid allocating new objects in many cases.*/public static Message obtain() {synchronized (sPoolSync) {if (sPool != null) {Message m = sPool;sPool = m.next;m.next = null;m.flags = 0; // clear in-use flagsPoolSize--;return m;}}return new Message();}public void recycle() {if (isInUse()) {if (gCheckRecycle) {throw new IllegalStateException("This message cannot be recycled because it "+ "is still in use.");}return;}recycleUnchecked();}/*** Recycles a Message that may be in-use.* Used internally by the MessageQueue and Looper when disposing of queued Messages.*/@UnsupportedAppUsagevoid recycleUnchecked() {// Mark the message as in use while it remains in the recycled object pool.// Clear out all other details.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 对象通过 next 属性构成一个链表。每个 Message 对象可以指向下一个可用的 Message,实现了简单的对象池。

当对象不再需要时(如在处理完消息后),调用recycle()可以将其放回池中(通过设置 next 指向池头 sPool),这样下次调用 obtain 时就能复用这些对象,而不是每次都新建。

在调用recycle()可以发现 有一个 isInUse()方法判断这个Message是否正在使用,这个其实不用开发者操心的,因为所有的消息都要经过Looper这个 “传送带”,内部自动回收,翻开Looper的源码文件你会发现在loopOnce方法中最后会调用 msg.recycleUnchecked(),如果你进行了某种自定义操作,导致 Message 未能通过正常的 Handler 流程处理,那么你可能需要手动调用 msg.recycle()

简单概括就是:一条由Message 组成的链表,你想用Message时,就从这个链表上 掐掉一个Message来使用,这个掐掉操作就是将m.next = null,当你不再使用时 就将其放回到链表头,操作就是 next = sPoolsPool = this

5. 优缺点


优点:

  1. 节省内存空间。
  2. 提高性能,特别是创建和管理大量对象时。

缺点:

  1. 外部状态管理可能导致系统逻辑混乱。

6. 应用场景


  • 游戏中的角色、场景元素(如树、建筑)等。
  • 文本处理系统中的字符、字体。
  • 大量相似对象需要频繁创建的场景。

7. 总结


享元模式通过共享对象来优化内存使用和性能,适合于需要创建大量相似对象的场景,但设计复杂性和状态管理需要谨慎处理。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Godot游戏如何提升触感体验

在游戏世界中&#xff0c;触感体验至关重要&#xff0c;既能极大提升玩家沉浸感&#xff0c;让其深度融入游戏&#xff0c;在操作角色或与环境互动时&#xff0c;通过触感反馈获得身临其境的真实感&#xff08;比如动作游戏中角色攻击或受击时的振动反馈&#xff0c;能使玩家更…

STM8L101低功耗的理解

一.通过降低时钟频率来降低功耗&#xff1a; 规格书如图 1.code 从flash启动&#xff0c;主频率是16Mhz时&#xff0c;功耗测量2.51ma左右&#xff0c;对应程序如下&#xff1a; 2.code从flash启动&#xff0c;主频率是2Mhz时&#xff08;上电默认值&#xff09;&#xff0c;功…

视频美颜SDK核心功能解析:打造高效直播美颜工具方案详解

随着直播行业的迅猛发展&#xff0c;用户对于直播画质和个人形象的要求越来越高。视频美颜SDK作为一项关键技术&#xff0c;已经成为各大直播平台和短视频应用的重要组成部分。通过实时美颜技术&#xff0c;用户能够在直播过程中呈现出更加理想的形象&#xff0c;从而提升直播体…

【计算机网络篇】物理层

本文主要介绍计算机网络第二章节的物理层&#xff0c;文中的内容是我认为的重点内容&#xff0c;并非所有。参考的教材是谢希仁老师编著的《计算机网络》第8版。跟学视频课为河南科技大学郑瑞娟老师所讲计网。 文章目录 &#x1f3af;一.基本概念及公式 &#x1f383;基本概念…

推荐系统-电商直播 多目标排序算法探秘

前言&#xff1a; 电商直播已经成为电商平台流量的主要入口&#xff0c;今天我们一起探讨推荐算法在直播中所面临的核心问题和解决方案。以下内容参考阿里1688的技术方案整理完成。 一、核心问题介绍 在电商网站中&#xff0c;用户的主要行为是在商品上的行为&#xff0c;直播…

STM32G431RBT6(蓝桥杯)串口(发送)

一、基础配置 (1) PA9和PA10就是串口对应在单片机上的端口 注意&#xff1a;一定要先选择PA9的TX和PA10的RX&#xff0c;再去打开异步的模式 (2) 二、查看单片机的端口连接至电脑的哪里 &#xff08;1&#xff09;此电脑->右击属性 &#xff08;2&#xff09;找到端…

轻量级RSS阅读器Fusion

什么是 Fusion &#xff1f; Fusion 是一款轻量级、自托管的 RSS 聚合器和阅读器。 软件主要特点&#xff1a; 自动分组、书签、搜索、嗅探信息导入/导出 OPML 文件支持 RSS、Atom、JSON 类型的 feed响应式、明/暗模式、PWA轻量级&#xff0c;自托管友好 使用 Golang 和 SQLit…

c语言面试字符串复制

1&#xff0c;下面这个函数的打印是什么&#xff1a; #include<stdio.h> #include<string.h>int main() {char str0[5], str1[] "welcome";strcpy(str0, str1);printf("str0:%s\r\n",str0);printf("str1:%s\r\n",str1); } larkla…

Linux:虚拟文件系统/proc和self进程

相关阅读 Linuxhttps://blog.csdn.net/weixin_45791458/category_12234591.html?spm1001.2014.3001.5482 /proc目录 在Linux操作系统中&#xff0c;目录/proc是一个虚拟文件系统&#xff0c;称为procfc&#xff0c;用于访问内核和系统的实时状态信息。这个文件系统不同于常规…

java-----IDE(集成开发环境)

IDE&#xff08;集成开发环境&#xff09; IDE&#xff08;集成开发环境&#xff09;-IDEA IDEA 介绍 1) IDEA 全称 IntelliJ IDEA2) 在业界被公认为最好的Java开发工具3) IDEA是JetBrains 公司的产品&#xff0c;总部位于捷克的首都布拉格4) 除了支持Java开发&#xff0c;还…

国标GB28181视频融合监控汇聚平台的方案实现及场景应用

Liveweb国标视频融合云平台基于端-边-云一体化架构&#xff0c;部署轻量简单、功能灵活多样&#xff0c;平台可支持多协议&#xff08;GB28181/RTSP/Onvif/海康SDK/Ehome/大华SDK/RTMP推流等&#xff09;、多类型设备接入(IPC/NVR/监控平台)&#xff0c;在视频能力上&#xff0…

Cloudera安装不再复杂:基础环境设置详解

Cloudera Manager是CDH市场领先的管理平台。它以其强大的数据管理和分析能力&#xff0c;帮助企业能够轻松驾驭海量数据&#xff0c;实现数据的实时分析与洞察。 作为业界第一的端到端 Apache Hadoop 的管理应用&#xff0c;Cloudera Manager对CDH的每个部件都提供了细粒度的可…

我与Linux的爱恋:进程优先级|进程切换

​ ​ &#x1f525;个人主页&#xff1a;guoguoqiang. &#x1f525;专栏&#xff1a;Linux的学习 文章目录 1.进程优先级1.什么是进程优先级&#xff1f;2.进程优先级的类型3.进程优先级的作用4.进程优先级的实现5.进程优先级的重要性6.查看系统进程7.修改进程优先级8.优先…

mysql笔记—sql性能分析

1.查看数据库各个语句的执行频次 show global/session status like ‘com__’ 2.慢查询 默认没有开启&#xff0c;需要手动开启&#xff08;在/etc/my.cnf中开启&#xff09; 开启后在localhost-slow.log中可以查询到慢查询的语句的相关信息&#xff1a; 3.explain 用法&…

Java 在 GIS 领域的学习路线?

Java是一门广泛应用于企业级开发的编程语言&#xff0c;而GIS则是一种常用于地理信息处理和分析的技术。将Java与GIS结合起来&#xff0c;可以在企业级应用中实现更多的功能和业务需求&#xff0c;且在实际领域越来越广泛。 Java在GIS中重要的作用 1、跨平台性 Java具有跨平台…

康佳集团的多元化战略:创新还是负担?

2023年&#xff0c;康佳集团豪赌“一轴两轮三驱动”战略&#xff0c;企图以消费电子和半导体为马&#xff0c;来驱动业绩的快车&#xff0c;但2024年的半年报如同一盆冷水&#xff0c;让所有期望化为泡影。 财报显示&#xff0c;康佳上半年营业总收入只有54.13亿元&#xff0c…

ActivityManagerService Activity的启动流程(2)

ActivityManagerService Activity的启动流程 简述 提到ActivityManagerService&#xff0c;最重要的流程之一就是启动Activity了。 这个流程比较复杂&#xff1a; 启动activity的调用链很长。业务逻辑很多&#xff0c;activity启动有很多flag&#xff0c;例如FLAG_ACTIVITY_…

激活Clion2024.2报错We could not validate your license解决

网上激活方法后报错We could not validate your license HLLIQN9GJ8. 只需要设置代理&#xff1a; 主机名&#xff1a;localhost 端口号&#xff1a;80 不为以下设置代理&#xff1a;*.github.com,plugins.jetbrains.com 然后重新激活就不会提示了。

mac安装JetBtains全家桶新版本时报错:Cannot start the IDE

mac安装JetBtains全家桶新版本时报错&#xff1a;Cannot start the IDE 前言报错信息解决方法 前言 作者使用的是Mac电脑&#xff0c;最近想要更新JetBrains相关工具的软件版本&#xff0c;但是在安装时突然报错&#xff0c;导致安装失败&#xff0c;现在将报错信息以及解决方…

FB FC里调用全局变量注意事项

PLC编程基础之数据类型、变量声明、全局变量和I/O映射 PLC编程基础之数据类型、变量声明、全局变量和I/O映射(CODESYS篇 )_codesys全局变量如何映射写入-CSDN博客文章浏览阅读6.3k次,点赞2次,收藏4次。本文介绍了CODESYS编程的基础知识,包括数据类型、变量声明、全局变量、…