享元模式(Flyweight Pattern),顾名思义。享是共享的意思。元是元数据。在Java程序设计中。主要用于减少创建对象的数量,以减少内存占用和提高性能。这种设计模式类似与缓存的设计。在Java中的String字符串缓存池。数据库连接池,线程池也都是是基于这种思想。
为了更加容易理解,还是来举个简单的栗子。
场景①: 当你画画时需要彩笔。彩笔存放在彩笔盒子里面。当我要用中颜色的彩笔时就去盒子里面拿,如果没有的话我就去买一支。用完之后继续放在彩盒子里面。下次要用还是去盒子里面去拿。
分析:
彩笔就是享元模式中的元数据。盒子就是存放元数据的一个块额外空间。买一支新的彩笔相当于创建一个新的对象。如果盒子里面已经有我们想要的彩笔,就不需要再重新去买了,这样就能重复利用这一支笔。
源码实现:
① 先创建一个彩笔接口。
public interface IColourPen {
/**
* 画画
* @param content 要画的类容
*/
void draw(String content);
}
② 创建一个生产彩笔的工厂。如果彩笔盒子里面有就直接取,没有就去买一支。
public class ColourPenFactory{
/**
* 缓存。相当于彩笔盒子
*/
private final static Map<ColourPenType, IColourPen> PEN_CACHE = new ConcurrentHashMap<>(8);
public static IColourPen get(ColourPenType colourPenType){
IColourPen pen = PEN_CACHE.get(colourPenType);
if (null == pen){
System.out.println(String.format("彩笔盒子没有颜色为%s的彩笔",colourPenType.name()));
switch (colourPenType.name()){
case "RED":
pen = new RedColourPen();
System.out.println("去商定给您买了一支新的红色彩笔");
break;
case "BLACK":
pen = new BlackColourPen();
System.out.println("去商定给您买了一支新的黑色彩笔");
break;
default:
throw new IllegalArgumentException("参数错误");
}
PEN_CACHE.put(colourPenType,pen);
}else {
System.out.println(String.format("彩笔盒子中已经存在%s的彩笔啦,直接从盒子里面取给你",colourPenType.name()));
}
return pen;
}
public enum ColourPenType {
RED, BLACK, GREEN, GRAY, BLUE,
}
}
③ 测试一下:
IColourPen pen1 = ColourPenFactory.get(ColourPenFactory.ColourPenType.RED);
IColourPen pen2 = ColourPenFactory.get(ColourPenFactory.ColourPenType.RED);
IColourPen pen3 = ColourPenFactory.get(ColourPenFactory.ColourPenType.RED);
System.out.println(pen1);
System.out.println(pen2);
System.out.println(pen3);
IColourPen pen4 = ColourPenFactory.get(ColourPenFactory.ColourPenType.BLACK);
System.out.println(pen4);
输出结果:
彩笔盒子没有颜色为RED的彩笔
去商定给您买了一支新的红色彩笔
彩笔盒子中已经存在RED的彩笔啦,直接从盒子里面取给你
彩笔盒子中已经存在RED的彩笔啦,直接从盒子里面取给你
com.dong.designs.bridge.RedColourPen@24d46ca6
com.dong.designs.bridge.RedColourPen@24d46ca6
com.dong.designs.bridge.RedColourPen@24d46ca6
彩笔盒子没有颜色为BLACK的彩笔
去商定给您买了一支新的黑色彩笔
com.dong.designs.bridge.BlackColourPen@372f7a8d
如上所示。就实现了资源的重复利用,节约了内存空间和cpu性能消耗。并且提高了运行效率。
可以发现享元模式跟单例模式非常相似。但是又不完全是。比如在String缓存池中。对于String类是用很多个不同的String实例的(以上样例不是从这个点去实现的享元模式。但是设计思想是一样的)。而单例模式要求一个类全局范围内必须只能存在一个实例。