今天,我们来分享结构型模式的另外一个成员:享元模式。
享元模式是一种结构型模式,它通过共享尽可能多的对象来减少内存使用和对象创建的数量,从而提高系统性能和效率。
在开始本文介绍之前,我们先来看一个题目:
问题来了?
答案是输出
true
false
为什么呢?
第一个输出true,是因为-128到127的数直接取自Cache,所以是同一个对象。
采用共享技术是享元模式的特点。接下来,我们一起来看下享元模式的介绍和示例。
意图
运用共享技术有效地支持大量细粒度的对象。
结构
享元模式的基本结构如下:
这里涉及到的参与者有如下几种:
抽象享元角色(Flyweight)
具体享元角色(ConcreteFlyweight)
非共享享元角色(UnsharedConcreteFlyweight)
享元工厂(FlyweightFactory)
客户端(Client)
示例一、茶馆小憩喝茶
春暖花开,我们以一群好朋友周末去西湖游玩,然后在西湖边茶馆喝茶闲聊为场景,给出一个简单的享元模式示例。
每个口味的茶对象是可以共享的,同口味的茶可以服务与不同桌号的顾客。
抽象享元角色
具体享元角色
非共享享元角色
此Context非常简单,本来还想加一个楼层信息的属性,简单化了,就只保留了一个桌号属性。TeaOrder参数也可以简化成一个int类型的tableNumber参数。
享元工厂
根据口味获取茶对象。如cache存在则直接从cache返回;如没有,则新建并放入map缓存起来,下次直接从缓存中获取,达到共享的效果。
Client.java(客户端)
Client端使用Factory来获取茶对象。
某次输出结果:
至此一个简单的享元模式例子就完成了。
从上面输出的结果来看,10个人点了十杯茶,包括3种口味,我们只创建了3个茶口味的对象,有7杯茶用到的Tea对象来自于共享。
示例二、坦克大战
小时候玩过的2D的坦克大战小游戏,它可以使用享元模式来提高性能和减少内存占用。比如地图中有很多的障碍物,可以是砖墙、草地、河流等,这些障碍物的特点是完全共享的,只是在不同的坐标位置显示出来即可。
我们以这些障碍物作为示例,再写一个简单的享元模式实现。
障碍物享元接口
具体障碍物享元
享元工厂
障碍物享元工厂,它负责创建和管理障碍物对象。
游戏客户端
Client端使用Factory来获取障碍物对象,然后使用障碍物对象的方法来绘制游戏场景。由于相同类型的障碍物共享相同的对象,因此可以有效地减少内存占用和对象创建。
某次运行结果:
由结果可见,我们渲染了很多障碍物,但是,其实也只有创建了3个对象,3个对象都会共享使用。同一类型的障碍物唯一的区别是显示的坐标一致。如果同类的障碍物显示的量很大,内存中其实只要维护少量的对象数量即可。
优点:
1、大幅度降低内存中对象的数量。
缺点:
1、享元模式使得系统更加复杂。为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。
2、享元模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。
线程池是享元模式的一种应用
在 Java 中,线程池是一种可以重用多个线程的机制,它能够提高程序的性能和效率。在使用线程池时,可以使用享元模式来管理线程的创建和共享,从而更加有效地利用系统资源。
具体来说,线程池中的线程对象可以看作是享元模式中的共享对象,而线程池本身则是享元工厂。当需要使用线程时,线程池从共享池中获取一个空闲的线程对象,而不是每次都创建新的线程对象,这样可以避免频繁地创建和销毁线程对象,从而提高系统性能和效率。
最后,再来看点原型模式和享元模式的一些区别。
原型模式和享元模式的区别
原型模式和享元模式都是为了提高系统性能和效率而设计的模式,但它们的应用场景和实现方式不同,需要根据具体情况进行选择。
应用场景
原型模式适用于创建复杂对象的情况,即需要耗费大量时间和资源的对象。通过克隆已有的对象,可以避免重新创建对象的过程,提高系统的性能和效率。
享元模式则适用于需要创建大量相似对象的情况,通过共享对象的内部状态,可以减少系统中对象的数量,从而节省内存空间和运行时的开销。
实现方式 原型模式的实现方式是通过克隆已有的对象来创建新的对象。实现 Cloneable 接口,并重写 clone() 方法,然后在需要的地方调用 clone() 方法创建新对象。
享元模式则需要将对象的内部状态和外部状态分离开来。内部状态是对象共享的部分,外部状态是对象不同的部分。通过将内部状态保存在共享池中,多个对象可以共享同一个内部状态,而将外部状态保存在对象的属性中,每个对象可以拥有自己的不同属性。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。