「设计模式你学全了吗」享元模式:减少对象数量

「设计模式你学全了吗」享元模式:减少对象数量

前言

《设计模式自习室》系列,顾名思义,本系列文章带你温习常见的设计模式。主要内容有:

该系列会逐步更新于我的博客和公众号(博客见文章底部),也希望各位观众老爷能够关注我的个人公众号:后端技术漫谈,不会错过精彩好看的文章。

系列文章回顾

结构型——享元模式 Flyweight Pattern

引子

主要用于减少创建对象的数量,以减少内存占用和提高性能。

在享元模式中通常会出现工厂模式,需要创建一个享元工厂来负责维护一个享元池(Flyweight Pool)用于存储具有相同内部状态的享元对象。

最经典的享元模式代码:

class FlyweightFactory {    //定义一个HashMap用于存储享元对象,实现享元池    private HashMap flyweights = newHashMap();    public Flyweight getFlyweight(String key){        //如果对象存在,则直接从享元池获取        if(flyweights.containsKey(key)){            return(Flyweight)flyweights.get(key);        }        //如果对象不存在,先创建一个新的对象添加到享元池中,然后返回        else {            Flyweight fw = newConcreteFlyweight();            flyweights.put(key,fw);            return fw;        }    }}

定义

运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式。

两个概念:

在享元类中要将内部状态和外部状态分开处理,通常将内部状态作为享元类的成员变量,而外部状态通过注入的方式添加到享元类中。

类图

如果看不懂UML类图,可以先粗略浏览下该图,想深入了解的话,可以继续谷歌,深入学习:

「设计模式你学全了吗」享元模式:减少对象数量

享元模式包含如下角色:

「设计模式你学全了吗」享元模式:减少对象数量

时序图

时序图(Sequence Diagram)是显示对象之间交互的图,这些对象是按时间顺序排列的。时序图中显示的是参与交互的对象及其对象之间消息交互的顺序。

我们可以大致浏览下时序图,如果感兴趣的小伙伴可以去深究一下:

「设计模式你学全了吗」享元模式:减少对象数量

代码实现

代码参考:

https://www.cnblogs.com/chenssy/p/3330555.html

假设:我们有一个绘图的应用程序,通过它我们可以出绘制各种各样的形状、颜色的图形,那么这里形状和颜色就是内部状态了,通过享元模式我们就可以实现该属性的共享了。

抽象享元类Flyweight:绘制图像的抽象方法

public abstract class Shape {    public abstract void draw();}

具体享元类ConcreteFlyweight:例子中则是一种绘制某种图像(圆形)的具体实现类,里面的颜色则是一个可以共享的内部对象。

public class Circle extends Shape{    private String color;    public Circle(String color){        this.color = color;    }    public void draw() {        System.out.println("画了一个" + color +"的圆形");    }}

享元工厂类FlyweightFactory:

利用了HashMap保存已经创建的颜色

public class FlyweightFactory{    static Map shapes = new HashMap();    public static Shape getShape(String key){        Shape shape = shapes.get(key);        //如果shape==null,表示不存在,则新建,并且保持到共享池中        if(shape == null){            shape = new Circle(key);            shapes.put(key, shape);        }        return shape;    }    public static int getSum(){        return shapes.size();    }}

客户端调用:

调用相同颜色时,会直接从HashMap中取那个颜色的对象,而不会重复创建相同颜色的对象。

public class Client {    public static void main(String[] args) {        Shape shape1 = FlyweightFactory.getShape("红色");        shape1.draw();        Shape shape2 = FlyweightFactory.getShape("灰色");        shape2.draw();        Shape shape3 = FlyweightFactory.getShape("绿色");        shape3.draw();        Shape shape4 = FlyweightFactory.getShape("红色");        shape4.draw();        Shape shape5 = FlyweightFactory.getShape("灰色");        shape5.draw();        Shape shape6 = FlyweightFactory.getShape("灰色");        shape6.draw();        System.out.println("一共绘制了"+FlyweightFactory.getSum()+"中颜色的圆形");    }}

使用场景举例

如果一个系统中存在大量的相同或者相似的对象,由于这类对象的大量使用,会造成系统内存的耗费,可以使用享元模式来减少系统中对象的数量。

Integer 中的享元模式

public static void main(String[] args) {        Integer i1 = 12 ;        Integer i2 = 12 ;        System.out.println(i1 == i2);        Integer b1 = 128 ;        Integer b2 = 128 ;        System.out.println(b1 == b2);    }

输出是

truefalse

在Java中,Integer是有缓存池的,缓存了-128~127的int对象

IntegerCache 缓存类:

//是Integer内部的私有静态类,里面的cache[]就是jdk事先缓存的Integer。private static class IntegerCache {    static final int low = -128;//区间的最低值    static final int high;//区间的最高值,后面默认赋值为127,也可以用户手动设置虚拟机参数    static final Integer cache[]; //缓存数组    static {        // high value may be configured by property        int h = 127;        //这里可以在运行时设置虚拟机参数来确定h  :-Djava.lang.Integer.IntegerCache.high=250        String integerCacheHighPropValue =            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");        if (integerCacheHighPropValue != null) {//用户设置了            int i = parseInt(integerCacheHighPropValue);            i = Math.max(i, 127);//虽然设置了但是还是不能小于127            // 也不能超过最大值            h = Math.min(i, Integer.MAX_VALUE - (-low) -1);        }        high = h;        cache = new Integer[(high - low) + 1];        int j = low;        //循环将区间的数赋值给cache[]数组        for(int k = 0; k < cache.length; k++)            cache[k] = new Integer(j++);    }    private IntegerCache() {}}

其他

同理,Long也有缓存池。

String类定义为final(不可改变的),JVM中字符串一般保存在字符串常量池中,java会确保一个字符串在常量池中只有一个拷贝,这个字符串常量池在JDK6.0以前是位于常量池中,位于永久代,而在JDK7.0中,JVM将其从永久代拿出来放置于堆中。

详细可参考:

http://laijianfeng.org/2018/09/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E4%BA%AB%E5%85%83%E6%A8%A1%E5%BC%8F%E5%8F%8A%E5%85%B8%E5%9E%8B%E5%BA%94%E7%94%A8/

优缺点

优点

缺点

参考

关注我

我是一名后端开发工程师。

主要关注后端开发,数据安全,爬虫,物联网,边缘计算等方向,欢迎交流。

各大平台都可以找到我

原创博客主要内容

个人公众号:后端技术漫谈

「设计模式你学全了吗」享元模式:减少对象数量

公众号:后端技术漫谈.jpg

如果文章对你有帮助,不妨收藏,投币,转发,在看起来~

展开阅读全文

页面更新:2024-05-29

标签:对象   模式   常量   时序   字符串   缓存   自习室   公众   数量   工厂   颜色   状态   代码   系列   数码   系统   技术

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top