什么是享元模式
“享元”,这是什么,这词不是很常见啊,不像工厂模式、建造者模式等,看见名字就能大概猜个八九不离十。
- 享,即共享。
- 元,是指一个单位,或者说是一个对象。
享元模式是运用共享技术有效地支持大量细粒度的对象的设计模式。
由于是细粒度单位的共享,享元模式又叫蝇量模式。
原理图
注意:内部状态与外部状态
使用享元模式,一定要分清什么可以共享(内部状态),什么不能共享(外部状态)。
- 内部状态是指对象共享出来的信息,储存在享元对象内部且不会随着环境的改变而改变。
- 外部状态是指对象得以依赖的一个标记,是随着环境的改变而改变的、不可共享的状态。
比如一盘围棋比赛,有黑白两种棋子,有361个落点。如果不适用享元模式,每一个落点都需要new一个棋子,即使服务器可以撑得住一场对局的进行,那么同时上万场呢?
对于一个颜色棋子来说,他们的外形、颜色是一样的,只是落点不同。那么将落点这个属性分离出去,仅仅需要两个棋子实例就足以应对所有的对局。
在这里,外形、颜色等细粒度的参数,是棋子的内部状态,而落点这样细粒度的参数是棋子的外部状态。
为什么要用享元模式
老李收编了一支乐队
李云龙打仗回来,发现了草丛里有一支乐队,便让乐队吹了一曲,感觉不错。收编了吧,不过这曲子,得换成咱八路的曲子。
战争时期,乐队也不是频繁出现的队伍,只在重大仪式时才会演奏,原来给原部队奏乐,现在给共八路奏乐,也不会出现同时奏乐的冲突(毕竟被收编了嘛)。
用代码的逻辑描述一下收编,怎么收编?怎么换成八路的曲子?
- 按照原有乐队,复制粘贴一份,改改奏乐的类型。
- 但是这不就有俩乐队了,不合适
- 找到这个乐队的类,再new一个。
- 现在俩乐队,曲一样,不合适。
- 用享元模式,乐队还是这么个乐队,教他们吹八路的曲子。
- 既然是享元模式,共享什么?共享这个乐队(这是内在状态,乐队有几个人、都是谁、用的什么乐器……)
- 外部状态是什么?外部状态是曲子现在是八路的曲子,别人来做客,也能吹吹别人的曲子。
代码模拟
首先要有一个抽象乐队类:
public abstract class AbstractBand {
public abstract void play(Tune tune);
}
有一个曲子类:
public class Tune {
private String name;
public Tune(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
有一支乐队:
public class Band extends AbstractBand {
private String name;
public Band(String name) {
this.name = name;
}
@Override
public void play(Tune tune) {
System.out.println(name + "演奏" + tune.getName());
}
}
用于管理乐队的“乐队工厂”:
import java.util.HashMap;
import java.util.Map;
public class BandFactory {
private Map<String, Band> bands = new HashMap();
public AbstractBand getBand(String name) {
if (!bands.containsKey(name)) {
bands.put(name, new Band(name));
}
return bands.get(name);
}
public int getTunesNumber(){
return bands.size();
}
}
李云龙:
public class LiYunLong {
public static void main(String[] args) {
BandFactory factory = new BandFactory();
AbstractBand band1 = factory.getBand("八路的乐队");
AbstractBand band2 = factory.getBand("八路的乐队");
Tune tune1 = new Tune("八路的曲子");
Tune tune2 = new Tune("国军的曲子");
band1.play(tune1);
band2.play(tune2);
System.out.println("现在的乐队数:" + factory.getTunesNumber());
}
}
输出结果:
八路的乐队演奏八路的曲子
八路的乐队演奏国军的曲子
现在的乐队数:1
当前类图
享元模式和单例模式很像?
需要回顾单例模式可以点击链接进行跳转
同样都是减少new的次数,同样都是一个对象给不同的调用方调用,他俩似乎还真有点相似。
需要注意的一点是,单例模式是创建型设计模式,享元模式是结构型设计模式。
关于二者不同点:
- 单例模式是整个应用系统共用一个实例对象;享元模式是整个系统共用好几个同类型对象。
- 单例模式绝对不会重复创建第二个对象,享元模式是按需分配,不够会进行创建。
关于享元模式怎么共享:
享元模式的共享对象在使用时是线程私有的,是有借有还的,在宏观上是共享的。
关于连接池:
连接池本身是单例模式,但是连接池里的多个连接对象是享元模式。