Android设计模式详解之享元模式

news2024/9/29 3:23:36

前言

享元模式是对象池的一种实现,用来尽可能减少内存使用量,适合用于可能存在大量重复对象的场景,来缓存可共享的对象;

定义:使用共享对象可有效地支持大量的细粒度的对象;

使用场景:

  • 系统中存在大量的相似对象;
  • 细粒度的对象都具备较接近的外部状态,而且内部状态与环境无关,也就是说对象没有特定身份;
  • 需要缓冲池的场景;

UML类图:
享元模式UML
Flyweight:享元对象抽象基类或者接口;

ConcreteFlyweight:具体的享元对象;

FlyweightFactory:享元工厂,负责管理享元对象池和创建享元对象;

示例代码

这里以读书进行举例,现在想阅读三国演义,但家里没有那就需要去买一本(享元工厂生产一本三国),读完了又想看水浒传,家里也没有那也需要去买一本(享元工厂生产一本水浒),回过头,又想要在读一遍三国,那就不再在去买了,直接找到原来的一本读就好了;

下面用享元模式实现:

  • 定义抽象享元类,Book
/**
 * 享元对象抽象基类
 */
interface Book {

    /**
     * readBook
     */
    fun readBook()
}
  • 定义具体享元对象,ConcreteBook
/**
 * 具体的书籍,具体的享元对象
 * @param name 图书名称
 */
class ConcreteBook(private val name: String) : Book {

    override fun readBook() {
        println("当前正在阅读:$name")
    }
}
  • 定义享元工厂,BookFactory
/**
 * 图书工厂
 */
object BookFactory {
    private val bookMaps = hashMapOf<String, Book>()


    fun getBook(name: String): ConcreteBook {
        return if (bookMaps.containsKey(name)) {
            println("家里有该书籍,直接找到")
            bookMaps[name] as ConcreteBook
        } else {
            println("家里没有该书籍,去买一本")
            val book = ConcreteBook(name)
            bookMaps[name] = book
            book
        }
    }
}
  • 编写调用类,验证功能
object Test {

    @JvmStatic
    fun main(args: Array<String>) {
        //阅读三国演义
        val book1 = BookFactory.getBook("三国演义")
        book1.readBook()
        println("============================")
        //阅读水浒传
        val book2 = BookFactory.getBook("水浒传")
        book2.readBook()
        println("============================")
        //再读一遍三国演义
        val book3 = BookFactory.getBook("三国演义")
        book3.readBook()
    }
}

输出结果如下:

家里没有该书籍,去买一本
当前正在阅读:三国演义
============================
家里没有该书籍,去买一本
当前正在阅读:水浒传
============================
家里有该书籍,直接找到
当前正在阅读:三国演义

Android源码中的享元模式

  • Message,熟悉Android消息机制的同学,对于Message肯定不陌生,我们废话不多说,直接看源码:
public final class Message implements Parcelable {
  	
  	//message相关信息
    public int what;
    public int arg1;
    public int arg2;
    public Object obj;
    public Messenger replyTo;
	//可以看出message是一个链表结构
     Message next;

    public static final Object sPoolSync = new Object();
    private static Message sPool;
    //当前消息池的大小
    private static int sPoolSize = 0;
	//消息池中最多缓存50个message
    private static final int MAX_POOL_SIZE = 50;

    private static boolean gCheckRecycle = true;
	
	//如果sPool不为null,则从消息池中取消息,否则直接new Message()对象;
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
            	//从链表头取出Message
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }
	
	//进行回收
  public void recycle() {
  		//如果当前正在使用,则调用recycle方法抛异常
        if (isInUse()) {
            if (gCheckRecycle) {
                throw new IllegalStateException("This message cannot be recycled because it "
                        + "is still in use.");
            }
            return;
        }
        recycleUnchecked();
    }
	
	//回收处理,清除相关信息,并将message插入到消息池中
    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) {
        	//判断消息池不满50时,将消息插入到链表头部
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }


}

从上面我们可以看出,调用Message.obtain()方法会从消息缓存池中取消息,这也是为什么推荐大家使用Message.obtain()方法而不是直接new Message()的原因,当Message被回收的时候,会清除相关信息,将消息存放到消息池中,从而实现消息的重复利用,典型的享元模式!!!

总结

优点:

  • 大幅度地降低内存中对象的数量,降低程序内存占用;

缺点:

  • 使得系统更加复杂,为了使对象可以共享,需要将一些状态外部化,使得程序的逻辑复杂化;
  • 将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长;

结语

如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )

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

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

相关文章

STM32/51单片机实训day7——电机驱动|ULN2003A步进电机|Proteus电路设计|旋转角度控制函数|驱动函数|Keil5程序设计

目录 1 ULN2003A步进电机简介 2 步进电机电路设计 3 旋转角度控制函数 4 程序设计 motor.c motor.h 前期LCD参考文章&#xff1a;​​​​​​​ 内 容&#xff1a;编程实现控制步进电机旋转不同角度 学 时&#xff1a;3学时 知识点&#xff1a; GPIO配置、步进电机…

【pygame学习_5】窗口设计

1、引言 窗体是游戏的交互界面&#xff0c;一般我们会遇到窗口大小可调&#xff0c;窗口无边框&#xff0c;全屏显示&#xff0c;最小化设计&#xff0c;改名字&#xff0c;换图标等设计需求。 屏幕绘制有如下重要函数&#xff1a; 2、屏幕模式函数 pygame.display.set.mode …

Event Loop

javascript是单线程语言 那么&#xff0c;你可能要问&#xff0c;javascript为什么是单线程&#xff0c;难道不能实现多线程吗&#xff1f; 这跟历史有关系。javascript从诞生的时候就是单线程&#xff0c;原因大概是不想让浏览器变得太复杂&#xff0c;因为多线程需要共享资源…

dark room - 2020 年苹果设计奖得主,一个足够强大的照片视频编辑器

dark room - 2020 年苹果设计奖得主&#xff0c;一个足够强大的照片视频编辑器 2020年苹果设计奖得主 2015年App Store最佳应用 Darkroom 是一个高级照片和视频编辑器。它对业余摄影师来说很容易操作&#xff0c;但对专业摄影师来说足够强大。 下载 ➤ Darkroom 下载安装 ⇲…

七十二——八十八

七十二、JavaScript——面向对象简介 面向对象编程&#xff08;OOP) 1. 程序是干嘛的 - 程序是现实世界的抽象&#xff08;照片就是对人的抽象&#xff09; 2. 对象是干嘛的&#xff1f; - 一个事物抽象到程序后就变成了对象 - 在程序的试接中&#xff0c;一切皆对象 - 一个事物…

来到CSDN一周年(hacker的2022年终总结)

✅作者简介&#xff1a;CSDN内容合伙人、阿里云专家博主、51CTO专家博主、新星计划第三季python赛道Top1&#x1f3c6; &#x1f4c3;个人主页&#xff1a;hacker707的csdn博客 &#x1f4ac;个人格言&#xff1a;不断的翻越一座又一座的高山&#xff0c;那样的人生才是我想要的…

【数据结构】排序算法大总结

文章目录1. 排序的概念及运用2. 常见排序算法的实现2.1 插入排序2.1.1 直接插入排序2.1.2 希尔排序2.2 选择排序2.2.1 直接选择排序2.2.2 堆排序2.3 交换排序2.3.1 冒泡排序2.3.1 快速排序小区间优化hoare版本挖坑法前后指针法2.3.2 快排非递归2.4 归并排序2.4.1 归并排序递归2…

本地缓存天花板-Caffeine

前言 caffeine是一款高性能的本地缓存组件&#xff0c;关于它的定义&#xff0c;官方描述如下&#xff1a; Caffeine is a high performance, near optimal caching library. 翻译过来就是Caffeine是一款高性能、最优缓存库。 同时文档中也说明了caffeine是受Google guava启发…

【Git】一文带你入门Git分布式版本控制系统(分支管理策略、Bug分支)

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;也会涉及到服务端 &#x1f4c3;个人状态&#xff1a; 在校大学生一枚&#xff0c;已拿多个前端 offer&#xff08;秋招&#xff09; &#x1f680;未…

Eth04 - Eth分层模块架构和索引方案

文章目录 1 Eth分层模块架构2 索引方案3 发送成功和接收成功回调函数传送门 ==>> AutoSAR入门和实战系列总目录 1 Eth分层模块架构 下面的图片表明了以太网控制器驱动程序和硬件的关系;从EthIf看来,要通过以太网控制器层去访问以太网控制器硬件,以太网控制器层有多…

AcWing1204.错误票据——学习笔记

题目&#xff1a;1204. 错误票据 - AcWing题库https://www.acwing.com/problem/content/description/1206/ import java.util.Scanner;public class Main {public static void main(String args[]){Scanner input new Scanner(System.in);int line input.nextInt();int loseI…

Python开发环境

1. Python开发环境 开发环境&#xff0c;英文是IDE&#xff08;Integrated Development Environment 集成开发环境&#xff09;。 不要纠结于使用哪个开发环境。开发环境本质上就是对Python解释器python.exe的封装&#xff0c;核心都一样。可以说:“开发环境IDE&#xff0c;只…

SpringCloud(10)— Elasticsearch集群

SpringCloud&#xff08;10&#xff09;— Elasticsearch集群 一 搭建ES集群 单机的 Elasticsearch 做数据存储&#xff0c;必然面临两个问题&#xff1a;海量数据存储问题&#xff0c;单点故障等 海量数据存储问题&#xff1a;将索引库从逻辑上拆分为 N 个分片&#xff08;…

直播回顾 | 如何运用数智化助力光伏上游产业节能降碳?

12月29日&#xff0c;【始祖双碳研习社-行业解决方案】系列直播课第一期直播顺利举办。 始祖科技解决方案专家张开宇在本次直播上进行了以《如何运用数智化助力光伏上游产业节能降碳》的主题分享&#xff0c;详细介绍了光伏行业产业链分析、光伏行业节能减排的现状与挑战、数智…

【Javassist】快速入门系列12 当检测到catch语句时在catch前插入代码

系列文章目录 01 在方法体的开头或结尾插入代码 02 使用Javassist实现方法执行时间统计 03 使用Javassist实现方法异常处理 04 使用Javassist更改整个方法体 05 当有指定方法调用时替换方法调用的内容 06 当有构造方法调用时替换方法调用的内容 07 当检测到字段被访问时使用语…

【C++学习】vector的使用及模拟实现

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《C学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; vector的使用及模拟实现&#x1f387;构造函数&#x1f9e8;模拟实现&#x1f9e8;vector的扩容机制&…

力扣(LeetCode)363. 矩形区域不超过 K 的最大数值和(2022.12.30)

给你一个 m x n 的矩阵 matrix 和一个整数 k &#xff0c;找出并返回矩阵内部矩形区域的不超过 k 的最大数值和。 题目数据保证总会存在一个数值和不超过 k 的矩形区域。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,0,1],[0,-2,3]], k 2 输出&#xff1a;2 解释&…

2022年-年度总结报告

目录1.攻克的技术难题问题1&#xff1a;2.学习的新技术1.system系统的学习2.网络3.游戏22年总结23年的计划1.先给自己画个大饼2.计划内的小饼1.攻克的技术难题 问题1&#xff1a; 跑VTS测试的时候&#xff0c;mkfs.exfat挂测失败&#xff0c;VTS刷最新的谷歌gsi没有过&#x…

大文件传输如何帮助媒体行业

过去几年&#xff0c;随着分辨率从4k到6k再到8k的升级&#xff0c;观众已经适应了高分辨率的时代。然而&#xff0c;许多媒体工作室的工作流程还停留在过去。 TB甚至PB大小的材料的传输让从业者无所适从。这就是高速文件传输对媒体行业有很大帮助的原因。 什么是大文件传输&am…

81.【SpringMVC】

SpringMVC(一)、认识MVC三层架构1.回顾MVC(1).什么是MVC三层框架(2).MVC要做那些事情?(3).常见的MVC三层框架结构(4).知识拓展2.代码回顾3.什么是SpringMVC(二)、第一个SpringMVC0.前提1.搭建环境2.配置WEB-INF的XML配置文件3.在资源Resource的包下设置springmvc-servlet.xml4…