设计模式学习(十二):享元模式

设计模式,学习,十二,模式 · 浏览次数 : 328

小编点评

**享元模式**是一种结构型设计模式,它可以有效地支持大量细粒度的对象。 **主要优势:** * 减少内存消耗 * 改善性能 * 降低垃圾回收频率 **设计模式的具体实现:** * 创建一个 `BulletPool` 类,负责管理子弹对象。 * 在 `getBullet` 方法中,遍历 `bullets` 列表,查找当前时间内的可用的子弹。 * 如果找到可用的子弹,返回它。 * 如果没有可用的子弹,创建一个新的子弹并返回。 **优缺点:** **优点:** * 减少内存消耗 * 改善性能 **缺点:** * 可能会导致内存溢出 * 垃圾回收频率可能会降低 **其他优化方法:** * 优化业务逻辑,尽量少的创建一次性对象。 * 使用 `reuse` 或 `cache` 等技术优化对象创建。 * 使用 `ThreadLocal` 等技术实现对象共享。

正文

设计模式学习(十二):享元模式

作者:Grey

原文地址:

博客园:设计模式学习(十二):享元模式

CSDN:设计模式学习(十二):享元模式

享元模式

享元模式是一种结构型模式。

一个应用场景是:运用共享技术有效地支持大量细粒度的对象。主要解决

在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。

假设我们有一个子弹类,同时我们设计一个子弹池,子弹池负责提供子弹

public class BulletPool {
    List<Bullet> bullets = new ArrayList<>();
    {
        for (int i = 0; i < 10; i++) {
            bullets.add(new Bullet(true));
        }
    }
    public Bullet getBullet() {
        for (int i = 0; i < bullets.size(); i++) {
            if (bullets.get(i).living) {
                return bullets.get(i);
            }
        }
        return new Bullet(true);
    }
}

可以看到 getBullet 逻辑,如果池子中有子弹,就拿池中的子弹,如果没有,就 new 一个新的子弹返回。

上述示例的 UML 图如下

image

享元模式应用

  • 使用对象池对高并发下的内存进行管理

对于开发者来说,垃圾回收是不可控的,而且是无法避免的。但是,我们还是可以通过一些方法来降低垃圾回收的频率,减少进程暂停的时长。我们知道,只有使用过被丢弃的对象才是垃圾回收的目标,所以,我们需要想办法在处理大量请求的同时,尽量少的产生这种一次性对象。最有效的方法就是,优化你的代码中处理请求的业务逻辑,尽量少的创建一次性对象,特别是占用内存较大的对象。比如说,我们可以把收到请求的 Request 对象在业务流程中一直传递下去,而不是每执行一个步骤,就创建一个内容和 Request 对象差不多的新对象。这里面没有多少通用的优化方法。对于需要频繁使用,占用内存较大的一次性对象,我们可以考虑自行回收并重用这些对象。实现的方法是这样的:我们可以为这些对象建立一个对象池。收到请求后,在对象池内申请一个对象,使用完后再放回到对象池中,这样就可以反复地重用这些对象,非常有效地避免频繁触发垃圾回收。

  • Java 中 Boolean 类的valueOf(boolean b) 方法 ,这个方法返回的 Boolean 对象不会新 new 出来,而是复用的同一个, 源码如下:
public static Boolean valueOf(boolean b){
    return(b?TRUE:FALSE);
}
public static final Boolean TRUE=new Boolean(true);
public static final Boolean FALSE=new Boolean(false);
  • Netty 中的 Buffer 分配。

  • 连接池管理,例如:Apache Commons Pool

  • Java SE 中的 IntegerCache 类和 String 类

在 Java Integer 的实现中, -128 到 127 之间的整型对象会被事先创建好,缓存在 IntegerCache 类中。当我们使用自动装箱或者valueOf()来创建这个数值区间的整型对象时,会复用 IntegerCache 类事先创建好的对象。这里的 IntegerCache 类就是享元工厂类,事先创建好的整型对象就是享元对象。在Java 中的 String 类的实现中,JVM 开辟一块存储区专门存储字符串常量,这块存储区叫作字符串常量池,类似于 Integer 中的 IntegerCache 。不过,跟IntegerCache 不同的是,它并非事先创建好需要共享的对象,而是在程序的运行期间,根据需要来创建和缓存字符串常量。

注:Java 提供了两个配置 IntegerCache 的参数

//方法一:
-Djava.lang.Integer.IntegerCache.high=255
//方法二:
-XX:AutoBoxCacheMax=255

UML 和 代码

UML 图

代码

更多

设计模式学习专栏

参考资料

与设计模式学习(十二):享元模式相似的内容:

设计模式学习(十二):享元模式

设计模式学习(十二):享元模式 作者:Grey 原文地址: 博客园:设计模式学习(十二):享元模式 CSDN:设计模式学习(十二):享元模式 享元模式 享元模式是一种结构型模式。 一个应用场景是:运用共享技术有效地支持大量细粒度的对象。主要解决 在有大量对象时,有可能会造成内存溢出,我们把其中共同的

设计模式学习(十):门面模式

设计模式学习(十):门面模式 作者:Grey 原文地址: 博客园:设计模式学习(十):门面模式 CSDN:设计模式学习(十):门面模式 门面模式 门面模式是一种结构型模式。 门面模式为子系统提供一组统一的接口,定义一组高层接口让子系统更易用。 假设建造一个房子需要有如下三个步骤: 第一步,和泥 第二

设计模式学习(十一):组合模式

设计模式学习(十一):组合模式 作者:Grey 原文地址: 博客园:设计模式学习(十一):组合模式 CSDN:设计模式学习(十一):组合模式 组合模式 组合模式是一种结构型模式。 组合模式中,最常用的一个用法就是目录层级的遍历,话不多说,直接上代码,主方法中 public class Main {

设计模式学习(十三):观察者模式

设计模式学习(十三):观察者模式 作者:Grey 原文地址: 博客园:设计模式学习(十三):观察者模式 CSDN:设计模式学习(十三):观察者模式 观察者模式 观察者模式是一种行为型模式。在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知。 一般可以用做事件处理

设计模式学习(十四):模板方法

设计模式学习(十四):模板方法 作者:Grey 原文地址: 博客园:设计模式学习(十四):模板方法 CSDN:设计模式学习(十四):模板方法 模板方法 模板方法是一种行为型模式。 假设我们要实现一个游戏,这个游戏有「初始化」,「启动」,「结束」三个方法,那么可以定义一个游戏的模板: public a

设计模式学习(十五):策略模式

设计模式学习(十五):策略模式 作者:Grey 原文地址: 博客园:设计模式学习(十五):策略模式 CSDN:设计模式学习(十五):策略模式 策略模式 策略模式是一种行为型模式,它定义了一组算法,将每个算法都封装起来,并且使它们之间可以互换。 以实例来说明 假设我们有一个猫类,这个类里面有体重和身高

设计模式学习(十六):责任链模式

设计模式学习(十六):责任链模式 作者:Grey 原文地址: 博客园:设计模式学习(十六):责任链模式 CSDN:设计模式学习(十六):责任链模式 责任链模式 责任链模式是一种行为型模式。 举例说明:有一段文本需要过滤一系列敏感字,我们可以通过责任链模式来设计这个功能,假设文本是 scripts H

设计模式学习(十七):状态模式

设计模式学习(十七):状态模式 作者:Grey 原文地址: 博客园:设计模式学习(十七):状态模式 CSDN:设计模式学习(十七):状态模式 状态模式 状态模式是一种行为型模式。 对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。 举例说明: Person 有 Cry ,

设计模式学习(十八):迭代器模式

设计模式学习(十八):迭代器模式 作者:Grey 原文地址: 博客园:设计模式学习(十八):迭代器模式 CSDN:设计模式学习(十八):迭代器模式 迭代器模式 迭代器模式是一种行为型模式。 迭代器最典型的应用是容器遍历 模仿 JDK 的容器,我们自定义一个容器并实现 iterator 方法; 首先,

设计模式学习(十九):访问者模式

设计模式学习(十九):访问者模式 作者:Grey 原文地址: 博客园:设计模式学习(十九):访问者模式 CSDN:设计模式学习(十九):访问者模式 访问者模式 访问者模式是一种行为型模式。 访问者模式在结构不变的情况下动态改变对于内部元素的动作。 举例说明: 假设我们需要构造一台电脑,有主板( Bo