设计模式享元模式 简介 ( 定义 | 对象池 | 内部状态 | 外部状态 | 适用场景 | 相关角色 )

网友投稿 934 2022-05-29

文章目录

I . 享元模式 简介

II . 享元模式 内部状态 和 外部状态

III . 享元模式 适用场景

IV . 享元模式 优缺点

V . 享元模式 相关模式

VI . 享元模式 相关角色

1 . 享元模式 简介 :

享元模式的核心是

对象池 ,

使用对象时 , 先从对象池中获取对象 ,

如果对象池中没有 , 创建一个 , 放入对象池 , 然后再从对象池中获取 ;

( 只能从对象池中拿对象 , 不能自己创建 )

① 设计模式类型 :

结构性 ;

② 享元模式 概念 :

通过减少创建对象数量 , 改善应用中使用对象的结构 , 使用

共享对象 ( 对象池中的对象 )

, 支持多个

细粒度对象 ( 使用时的大量对象 ) ;

③ 好处 :

减少创建对象的数量 , 从而减少内存的占用 , 提高性能 ;

2 . 细粒度对象 和 共享对象 :

目的是为了提高程序性能 ;

① 细粒度对象 :

是内存中的数量庞大的对象 ;

实际使用的数量庞大的对象 ;

② 共享对象 :

多个细粒度对象共享的部分数据 ;

对象缓存池中存储的对象 ;

③ 举例说明 :

使用字符串值 “abc” ,

首次使用 , 创建该字符串 , 将其放入字符串缓存池中 , 这个缓存池中的字符串就是

"共享对象" ,

应用中要大量使用 “abc” 字符串 , 比如使用 10 万个 “abc” 字符串对象 , 这 10 万个字符串对象就是

"细粒度对象" ,

此时肯定不会创建这么多对象 , 这 10 万个对象使用时从字符串缓存池中查找缓存的那个

"共享对象"

即可 , 这样节省了很大的内存开销 ;

3 . 享元模式示例 :

Java 的 String 类型就是用了享元模式的设计模式 ;

① 定义字符串 : String str = "Hello" ;

② 内存中已有该字符串 :

如果之前已经有该字符串 , 就直接将字符串缓存池中的字符串返回 ,

【设计模式】享元模式 简介 ( 定义 | 对象池 | 内部状态 | 外部状态 | 适用场景 | 相关角色 )

③ 新字符串 :

如果内存中没有该字符串 , 就创建一个新的字符串 , 放入缓存池中 ;

享元模式就是池技术 , 如字符串池 , 数据库连接池 等 ;

使用对象时 , 先从池中查找 , 没有找到再创建该对象 , 然后放入对象池中 ;

4 . 享元模式使用策略 :

用户想要调用一个对象 , 去对象池中查找 , 如果对象池中有该对象 , 那么直接使用该对象 , 如果没有 , 创建该对象 , 放入对象池中 , 然后再从对象池中获取该对象 ;

对象对比 :

这里涉及到一个问题 , 如何确定对象池中的对象是不是用户想要使用的对象呢 ?

5 . 引入 内部状态 和 外部状态 :

对象对比问题引出这两个概念 , 对象中有很多数据 , 那么使用什么数据来确定两个对象是否一致呢 , 这里使用 对象的 外部状态 来确定 ;

① 内部状态 :

对象的内部状态不能作为对象对比的依据 , 所有对象的内部状态都是一样的数据 ;

② 外部状态 :

对象的外部状态每个都不一样 , 每个对象都有一个唯一 外部状态 值 , 类似于 身份证 , 哈希码 这一类的信息 ;

③ 身份标识 :

在线程池中 , 使用外部状态信息 , 唯一确定一个对象 , 作为对象的标识信息 ;

1 . 概念引入 :

区分这两个概念的目的是为了维护享元模式的对象池 , 当用户想要使用某个对象时 , 如何确定对象池中的对象是否是用户想要调用的对象呢 , 这里就需要一些数据进行对比 , 数据一致 , 就说明是用户想要的对象 , 数据不一致 , 就需要创建新对象 , 放入对象池 ;

① 内部状态 :

有些数据所有的对象都一样 , 显然不能当做对象一致性对比的依据 , 这就是 内部状态 ;

② 外部状态 :

有些数据每个对象都不一样 , 根据该数据确定对象的唯一性 , 相当于 哈希码 , 身份证号 , 档案编号 这一类的数据 , 这就是外部状态 ;

内部状态 和 外部状态 本质是 信息数据

2 . 内部状态 ( 共享信息 ) :

在享元模式中的对象中 , 不随环境改变而改变的信息 ;

① 共享信息 :

内部状态就是可以被共享的信息 ;

② 存储位置 :

该信息存储在享元对象内部 ;

③ 存储形式 :

该信息作为对象的附加数据 , 不在具体的对象中存储 , 可以被多个对象共享 ;

3 . 外部状态 ( 不可共享信息 ) :

随着外部环境改变 , 对象内部跟着改变 , 这部分内容就不能进行共享 ;

不可共享 :

外部状态不可被共享 , 每个值都必须在不同的对象中维护 ;

1 . 享元模式 适用场景 :

① 底层开发 :

某个系统的底层开发 , 对性能要求比较高 , 可使用享元模式 ;

② 缓冲池 :

系统中实例对象数量庞大 , 需要缓冲池处理这些对象 ;

2 . 享元模式使用前提 :

系统中存在大量的对象 , 这些对象状态大部分功能可以外部化 , 将这些功能抽离出来 , 只在内存中保留一份 ;

① 分离对象功能 :

系统中如果内存中持有大量对象 , 可能会溢出 , 将这些对象相同的部分分离出来 ;

② 用户调用行为 :

如果有相同的业务请求 , 则优先使用内存中已有的对象进行处理 , 避免使用大量相同的对象 ;

③ 注意 :

这里只有在内存中有大量相同对象时 , 才考虑享元模式 , 如果内存中某类型的对象数量较少 , 没有必要使用该模式 ;

1 . 享元模式 优点 :

① 降低内存占用 :

减少在内存中创建对象的数量 , 节省了内存 , 提高了效率 ;

② 减少创建对象开销 :

创建对象时需要占用一定的开销 , 如 new 操作 ; 可能构造函数中有访问 文件 , 数据库 , 网络 等操作 , 也可以避免这些开销 ;

2 . 享元模式 缺点 :

① 线程安全问题 :

在类中为了追求性能 , 一般使用的是 HashMap , ArrayList 等数据 , 这些数据结构都是线程不安全的 ; 使用 HashTable , Vector 线程安全了 , 但是性能会下降很多 ; 折中使用 ConcurrentHashMap 等 concurrent 包下的集合 ;

② 增加复杂性 :

将一个类拆解成多个类 , 系统复杂性肯定增加了 ;

1 . 享元模式 与 代理模式 :

代理模式需要代理某个类 , 生成该类需要花费较多的资源和时间 , 可以使用享元模式提高处理速度 ;

2 . 享元模式 与 单例模式 :

容器单例模式 , 复用对象 ;

1 . 抽象享元角色 :

抽象类 , 其中定义了 内部对象 , 外部对象 , 抽象行为 ;

① 内部对象 :

享元模式中 , 不关心该类数据 ;

② 外部对象 :

该值只能设置一次值 , 不能二次赋值 , 否则会造成对象池管理混乱 ; 一般要设置成 final 类型的 , 在构造函数中赋值 ;

③ 抽象行为 :

这是客户调用的方法 ;

客户使用享元模式时 , 创建的对象就是 抽象的享元角色 对象 , 调用的是抽象行为 ;

享元工厂管理时 , 也管理 抽象享元角色 对象 ;

2 . 具体享元角色 :

在构造函数中设置外部状态 , 实现自己的业务逻辑 ;

3 . 享元工厂角色 :

在享元工厂中 , 维护对象池 , 当用户调用 享元对象 时 , 从对象池中获取该对象 , 如果没有获取到 , 那么创建新的 享元对象 , 放入对象池中 , 并返回该对象 ;

4 . 用户调用 :

用户声明 抽象享元类对象 , 调用其定义的抽象行为 ;

任务调度

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Ubuntu 安装Qt
下一篇:UMA & NUMA
相关文章