享元模式
享元模式:
了解享元模式的 内部状态 和 外部状态
常量存放在常量池,变量存放在栈中,引用对象存放在堆中
Vector?
intern()?
享元模式:Flyweight Pattern
又叫 轻量级模式,是对象池的一种实现,可循环利用
线程池可以避免不停的创建和销毁多个对象
提供了减少对象数量从而改善应用所需的对象结构的方式
宗旨:共享细粒度对象,将多个对同一对象的访问集中起来,不必为每个访问者创建一个单独的对象,以此来降低内存的消耗
属于结构型模式
享元模式 把一个对象的状态分成内部状态 和 外部状态,内部状态即时不变的,外部状态是变化的,然后通过共享不变的部分,达到减少对象数量并节约内存的目的
享元模式的本质是 缓存共享对象,降低内存消耗
享元模式 有三个参与角色:
抽象享元角色(Flyweight): 享元对象抽象基类或接口,同时定义出对象的外部状态 和 内部状态 的接口或实现
具体享元角色(ConcreteFlyweight): 实现抽象角色定义的业务。该角色的 内部状态 处理应该与环境无关,不能出现会有一个操作改变内部状态,同时修改了外部状态
享元工厂(FlyweightFactory): 负责管理享元对象池 和 创建享元对象
应用场景:
生活中常见于:
各类房源共享 全国社保联网
当系统中多处需要同一组信息时,可以把信息封装到一个对象中,然后对该对象进行缓存,这样,一个对象就可以提供给多处需要使用的地方,避免大量同一对象的多次创建,消耗大量内存空间
享元模式 其实就是 工厂模式 的一个改进机制,享元模式 同样要求创建一个或一组对象,并且通过工厂方法生成对象的,只不过 享元模式 中为工厂方法增加了缓存这一功能。
主要总结以下应用场景:
1、常用于系统底层的开发,以便解决系统性能问题
2、系统有大量相似对象,需要缓冲池的场景
通用写法:
pattern.flyweight.general
使用享元模式实现共享池业务:
春节抢火车票
抢票软件 会将我们的信息缓存起来,然后定时检查余票信息
抽象享元角色 ITicket
具体享元角色 TrainTicket
享元工厂 TicketFactory
很多小伙伴疑惑,这不就是注册式单例模式吗? 对这就是注册式单例模式!
结构上像,但是享元模式重点在结构上,而不是在创建对象上
pattern.flyweight.ticket
数据库连接池:
使用 Connection 对象时,主要性能消耗在建立连接和关闭连接
为了提高 Connection 在调用时的性能,我们将 Connection 在调用前创建好的对象缓存起来,用的时候从缓存中取出,用完再放回去?达到资源重复利用的目的
pattern.flyweight.pool
这样的连接池,普遍应用于开源框架,有效提升底层的运行性能
源码中的体现:
Spring 中的享元模式
Integer 中的享元模式
Long 中的享元模式
Apache Commons Pool2 中的享元模式
用于从当保存对象的“容器”的对象,叫“对象池” Object Pool
PooledObject 池对象 用于封装对象(线程、数据库连接、TCP连接),将其包裹成可被池管理的对象
PooledObjectFactory 池对象工厂 定义了操作 PooledObject 实例生命周期的一些方法,PooledObjectFactory 必须实现线程安全
ObjectPool 对象池 ObjectPool 负责管理 PooledObject , 如:借出对象、返回对象、校验对象、有多少激活对象,多少空闲对象
享元模式的 内部状态 和 外部状态
提出了两个要求:细粒度 和 共享对象
内部状态:
指对象共享出来的信息,存储再享元对象内部,且不会随环境的改变而改变
外部状态:
指对象得依赖一个标记,是随着环境改变而改变的,不可共享的
比如:
连接池的的连接对象,保存再连接对象中的用户名、密码、连接url等信息,再创建对象时就设置好了,不会随环境的改变而改变,这些为内部状态。
而每个连接要回收利用时,我们需要给它标记成可用状态,这些为外部状态
享元模式和代理模式:
代理模式:功能增强
享元模式:资源利用,减少占用
享元模式和单例模式
优点:
减少对象的创建,降低内存中对象的数量,降低系统的内存,提供效率
减少内存之外的其他资源的占用
缺点:
关注 内、外部状态,关注线程安全问题
使得程序的逻辑复杂化
tom的开源项目
https://github.com/gupaoedu-tom/3party-tools/tree/master/py12306
作业:
1、你还能举出哪些关于享元模式的应用场景?。
图书馆书籍管理
共享单车(内部状态:有没有坏、颜色、款式、编码)
(外部状态:是否被租用)
共享车位(内部状态:人防车位、小车)
(外部状态:是否租用、占用)