设计模式(十二)享元模式

作者: 我犟不过你 | 来源:发表于2021-01-11 16:05 被阅读0次

1、概述

享元模式是一种结构型设计模式, 它摒弃了在每个对象中保存所有数据的方式, 通过共享多个对象所共有的相同状态, 让你能在有限的内存容量中载入更多对象。

享元模式只有一个目的: 将内存消耗最小化。

2、适用场景

仅在程序必须支持大量对象且没有足够的内存容量时使用享元模式。

3、实例

有以下场景:

有100000颗杨树树苗,需要种植。
其中杨树有颜色,名称,树高等属性。

种植杨树。

3.1 不使用享元模式

import java.util.Map;

/**
 * 树
 * @date: 2021/1/11
 * @author weirx
 * @version 3.0
 */
public class Tree {

    private String name;

    private String color;

    private Map<String,Object> other;

    public Map<String, Object> getOther() {
        return other;
    }

    public void setOther(Map<String, Object> other) {
        this.other = other;
    }

    public Tree(String name, String color, Map<String, Object> other, double high) {
        this.name = name;
        this.color = color;
        this.other = other;
        this.high = high;
    }

    private double high;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public double getHigh() {
        return high;
    }

    public void setHigh(double high) {
        this.high = high;
    }
}

测试类:


/**
 * 客户端
 * @date: 2021/1/4
 * @author weirx
 * @version 3.0
 */
public class TestDemo {

    public static void main(String arg[]) {
        System.out.println("开始种树");
        List<Tree> list = new ArrayList<>();
        for (int i = 0; i < 100000; i++) {
            list.add(new Tree("杨树", "绿色", new HashMap<>(),Math.random() * (10 - 5) + 5));
        }
        System.out.println("种植完成");
    }

}

3.2 使用享元模式

/**
 * 树
 * @date: 2021/1/11
 * @author weirx
 * @version 3.0
 */
public class Tree {

    private TreeBaseField baseField;
    
    private double high;

    public TreeBaseField getBaseField() {
        return baseField;
    }

    public void setBaseField(TreeBaseField baseField) {
        this.baseField = baseField;
    }

    public double getHigh() {
        return high;
    }

    public void setHigh(double high) {
        this.high = high;
    }

    public Tree(TreeBaseField baseField, double high) {
        this.baseField = baseField;
        this.high = high;
    }
}

抽出公共属性

/**
 * 树基本属性
 * @date: 2021/1/11
 * @author weirx
 * @version 3.0
 */
public class TreeBaseField {

    private String name;

    private String color;

    private Map<String,Object> map;

    public Map<String, Object> getMap() {
        return map;
    }

    public void setMap(Map<String, Object> map) {
        this.map = map;
    }

    public TreeBaseField(String name, String color, Map<String, Object> map) {
        this.name = name;
        this.color = color;
        this.map = map;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

享元工厂:

import org.apache.commons.lang3.ObjectUtils;

import java.util.HashMap;

/**
 * 享元工厂
 * @date: 2021/1/11
 * @author weirx
 * @version 3.0
 */
public class FlyweightBeanFactory {

    public static HashMap<String, TreeBaseField> map = new HashMap<>();

    public static TreeBaseField getBaseField(String name, String color) {
        TreeBaseField treeBaseField = map.get(name);
        if (ObjectUtils.isEmpty(treeBaseField)) {
            map.put(name, new TreeBaseField(name, color,new HashMap<>()));
        }
        return map.get(name);
    }
}

测试类:

import java.util.ArrayList;
import java.util.List;

/**
 * 测试类
 * @date: 2021/1/11
 * @author weirx
 * @version 3.0
 */
public class TestDemo {

    public static void main(String[] args) {
        List<Tree> list = new ArrayList<>();
        System.out.println("开始种树");
        for (int i = 0; i < 100000; i++) {
            list.add(new Tree(FlyweightBeanFactory.getBaseField("杨树", "绿色"),
                    Math.random() * (10 - 5) + 5));
        }
        System.out.println("种树完成");
    }
}

4、分析

这里我们使用jps命令和jstat命令进行内存分析:

不使用享元的情况下

E:\workspace\bssp-cloud\bssp-admin-front>jps
31844 TestDemo

E:\workspace\bssp-cloud\bssp-admin-front>jstat -gcutil 31844
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
  0.00   0.00  50.08   0.00  17.54  19.90      0    0.000     0    0.000    0.000

我们发现内存Eden区占用了50.08。

使用享元

E:\workspace\bssp-cloud\bssp-admin-front>jps
37124 TestDemo

E:\workspace\bssp-cloud\bssp-admin-front>jstat -gcutil 37124
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
  0.00   0.00  36.56   0.00  17.54  19.90      0    0.000     0    0.000    0.000

我们发现内存Eden区占用了36.56。

随着数据量的增加,这两个差距将会更大。

在数据量很小,甚至说主类,比如Tree,其属性很少,都是一些基本类型的,使用享元反而会导致内存占用增加。

5、总结

优点:
如果程序中有很多相似对象, 那么你将可以节省大量内存。

缺点:
1)代码复杂
2)每次使用对象时都增加了判断,增加计算成本。
3)通过实践来决定是否真的需要享元模式,否则会适得其反。

相关文章

  • 好程序员Java培训​分享java设计模式之享元模式

    好程序员Java培训​分享java设计模式之享元模式,Java设计模式中的享元模式。享元模式有点类似于单例...

  • 设计模式(十二)享元模式

    享元模式定义 享元模式是结构型设计模式的一种,是池技术的重要实现方式,它可以减少应用程序创建的对象,降低程序内存的...

  • 设计模式十二--享元模式

    定义 使用共享变量可有效地支持大量的细粒度对象。享元模式是以共享的方式高效的支持大量的细粒度对象。享元模式能做到共...

  • 设计模式(十二):享元模式

    运用共享技术有效地支持大量细粒度的对象。在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有...

  • 设计模式(十二)享元模式

    1、概述 享元模式是一种结构型设计模式, 它摒弃了在每个对象中保存所有数据的方式, 通过共享多个对象所共有的相同状...

  • Java设计模式——享元模式

    Java设计模式之享元模式 这期跟大家聊的的设计模式是享元模式,该模式也是结构模式。 简介 利用共享的方式解决大量...

  • Java设计模式_享元模式

    点击链接跳转:设计模式——享元模式

  • 二十一、享元模式

    1. 何为享元模式 定义:通过共享已存在的对象,减少创建对象内存开销的设计模式被称为享元模式。 享元模式和单例模式...

  • 享元模式

    swift实战-享元模式 概论:通过共享已存在的对象,减少创建对象内存开销的设计模式被称作享元模式 享元模式Fly...

  • 好程序员Java培训精讲  java设计模式—享元模式

    好程序员Java培训精讲 java设计模式—享元模式 一、关于享元模式 享元模式有点类似于单例模式,都是只生成一个...

网友评论

    本文标题:设计模式(十二)享元模式

    本文链接:https://www.haomeiwen.com/subject/gbgloktx.html