如有转载,请申明:
转载至 http://blog.youkuaiyun.com/qq_35064774/article/details/52097024
1 什么是享元模式
享元模式是对象的结构模式。享元模式以共享的方式高效地支持大量的细粒度对象。
享元对象能做到共享的关键是区分内蕴状态外蕴状态。
内蕴状态是存储在享元对象内部的,不会随着环境而改变,所以是可以共享的。
外蕴状态是随环境改变而改变的,所以不可共享。
2 如何实现享元模式
同样我们举个简单的例子。
* 加载图片是非常消耗资源的操作
* 假设现在总共只有几张图片,但运行过程中,需要频繁的在不同位置展示这些图片
题目说明很清楚,由于一张图片小的十几k,大的几M,是非常耗内存的,然而图片总共只有那几张。对于相同的图片,在内存中只需要存在一份即可,这个时候就可以考虑用享元模式。
把图片的所有字节看作是内蕴状态,而图片位置就是外蕴状态。
我们就可以定义出图片类,注意这个图片类是我们自己定义的,不要和官方库里面的类混淆了。
package com.ittianyu.flyweight;
public class Image {
private String name;
private byte[] bytes;
// name 作为内蕴状态
public Image(String name) {
super();
this.name = name;
// 为了简单,这里不做读取图片的操作,直接用个byte数组来表示
bytes = new byte[1024];
}
// 这里的x y坐标作为外蕴状态
public void show(int x, int y) {
System.out.println(name + " show in" + "(" + x + ", " + y + ")");
}
}
为了控制对象的产生,也就是为了共享,我们需要一个工厂类来生产对象。
package com.ittianyu.flyweight;
import java.util.HashMap;
import java.util.Map;
public class ImageFactory {
private static ImageFactory factory;
private Map<String, Image> maps = new HashMap<String, Image>();
// 懒汉单例模式
private ImageFactory(){}
public synchronized static ImageFactory getInstance() {
if(null == factory)
factory = new ImageFactory();
return factory;
}
public Image create(String name) {
if(maps.containsKey(name))
return maps.get(name);
Image image = new Image(name);
maps.put(name, image);
return image;
}
}
这个类里面,我们通过create方法来创建Image对象,创建的时候,我们先检查这个图片是否已经存在,如果存在,直接返回这个对象的引用,否则就创建一个,并放到map集合中。
最后是测试类。
package com.ittianyu.flyweight;
public class Test {
public static void main(String[] args) {
ImageFactory factory = ImageFactory.getInstance();
Image image1 = factory.create("image1.png");
Image image2 = factory.create("image2.png");
Image image3 = factory.create("image1.png");
Image image4 = factory.create("image1.png");
image1.show(0, 0);
image2.show(10, 10);
image3.show(4, 2);
image4.show(8, 3);
}
}
这个测试类中,我们在调用show方法时,需要传入坐标参数,这就是外蕴状态。
3 在什么情况下使用享元模式
引用《Java与模式》中的说明。
* 一个系统有大量的对象。
* 这些对象耗费大量的内存。
* 这些对象的状态中大部分都可以外部化。
* 这些对象可以按照内蕴状态分成很多的组,当把外蕴对象从对象中剔除时,每一个组都可以仅用一个对象代替。
4 享元模式的优点和缺点
优点:
* 可以大幅度降低内存中对象的数量。
缺点:
* 使得系统更加复杂。
* 享元对象将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。