享元模式的原理
所谓“享元”,顾名思义就是被共享的单元。享元模式的意图是复用对象,节省内存,前提是享元对象是不可变对象。具体来讲,当一个系统中存在大量重复对象的时候,我们就可以利用享元模式,将对象设计成享元,在内存中只保留一份实例,供多处代码引用,这样可以减少内存中对象的数量,以起到节省内存的目的。实际上,不仅仅相同对象可以设计成享元,对于相似对象,也可以将这些对象中相同的部分(字段),提取出来设计成享元,让这些大量相似对象引用这些享元。
享元模式的实现
享元模式的代码实现非常简单,主要是通过工厂模式,在工厂类中,通过一个 Map 或者 List 来缓存已经创建好的享元对象,以达到复用的目的。
享元模式 VS 单例、缓存、对象池
区别两种设计模式,不能光看代码实现,而是要看设计意图,也就是要解决的问题。可以用简单几句话来概括一下它们之间的区别。应用单例模式是为了保证对象全局唯一。应用享元模式是为了实现对象复用,节省内存。缓存是为了提高访问效率,而非复用。池化技术中的“复用”理解为“重复使用”,主要是为了节省时间。
享元模式的应用
在 Java Integer 的实现中,-128 到 127 之间的整型对象会被事先创建好,缓存在 IntegerCache 类中。当使用自动装箱或者 valueOf() 来创建这个数值区间的整型对象时,会复用 IntegerCache 类事先创建好的对象。这里的 IntegerCache 类就是享元工厂类,事先创建好的整型对象就是享元对象。
在 Java String 类的实现中,JVM 开辟一块存储区专门存储字符串常量,这块存储区叫作字符串常量池,类似于 Integer 中的 IntegerCache。不过,跟 IntegerCache 不同的是,它并非事先创建好需要共享的对象,而是在程序的运行期间,根据需要来创建和缓存字符串常量。
享元模式对 JVM 的垃圾回收并不友好。因为享元工厂类一直保存了对享元对象的引用,这就导致享元对象在没有任何代码使用的情况下,也并不会被 JVM 垃圾回收机制自动回收掉。因此,在某些情况下,如果对象的生命周期很短,也不会被密集使用,利用享元模式反倒可能会浪费更多的内存。所以,除非经过线上验证,利用享元模式真的可以大大节省内存,否则,就不要过度使用这个模式。
551

被折叠的 条评论
为什么被折叠?



