《设计模式自习室》系列,顾名思义,本系列文章带你温习常见的设计模式。主要内容有:
该系列会逐步更新于我的博客和公众号(博客见文章底部),也希望各位观众老爷能够关注我的个人公众号:后端技术漫谈,不会错过精彩好看的文章。
主要用于减少创建对象的数量,以减少内存占用和提高性能。
在享元模式中通常会出现工厂模式,需要创建一个享元工厂来负责维护一个享元池(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()+"中颜色的圆形"); }}
如果一个系统中存在大量的相同或者相似的对象,由于这类对象的大量使用,会造成系统内存的耗费,可以使用享元模式来减少系统中对象的数量。
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
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号