转眼就要 6 月份了,时间过的好快勒。
说到享元模式,第一个想到的应该就是池技术了,String常量池、数据库连接池、缓冲池等等都是享元模式的应用,所以说享元模式是池技术的重要实现方式。
比如我们每次创建字符串对象时,都需要创建一个新的字符串对象的话,内存开销会很大,所以如果第一次创建了字符串对象“adam“,下次再创建相同的字符串”adam“时,只是把它的引用指向”adam“,这样就实现了”adam“字符串再内存中的共享。
举个最简单的例子,网络联机下棋的时候,一台服务器连接了多个客户端(玩家),如果我们每个棋子都要创建对象,那一盘棋可能就有上百个对象产生,玩家多点的话,因为内存空间有限,一台服务器就难以支持了,所以这里要使用享元模式,将棋子对象减少到几个实例。下面给出享元模式的定义。
享元模式(Flyweight),运用共享技术有效地支持大量细粒度的对象。UML结构图如下:
其中,Flyweight是抽象享元角色。它是产品的抽象类,同时定义出对象的外部状态和内部状态(外部状态及内部状态相关内容见后方)的接口或实现;ConcreteFlyweight是具体享元角色,是具体的产品类,实现抽象角色定义的业务;UnsharedConcreteFlyweight是不可共享的享元角色,一般不会出现在享元工厂中;FlyweightFactory是享元工厂,它用于构造一个池容器,同时提供从池中获得对象的方法。
1. Flyweight抽象类
所有具体享元类的超类或接口,通过这个接口,Flyweight可以接受并作用于外部状态。
public abstract class Flyweight {
//内部状态
public String intrinsic;
//外部状态
protected final String extrinsic;
//要求享元角色必须接受外部状态
public Flyweight(String extrinsic) {
this.extrinsic = extrinsic;
}
//定义业务操作
public abstract void operate(int extrinsic);
public String getIntrinsic() {
return intrinsic;
}
public void setIntrinsic(String intrinsic) {
this.intrinsic = intrinsic;
}
}
- ConcreteFlyweight类
继承Flyweight超类或实现Flyweight接口,并为其内部状态增加存储空间。
public class ConcreteFlyweight extends Flyweight {
//接受外部状态
public ConcreteFlyweight(String extrinsic) {
super(extrinsic);
}
//根据外部状态进行逻辑处理
@Override
public void operate(int extrinsic) {
System.out.println("具体Flyweight:" + extrinsic);
}
}
UnsharedConcreteFlyweight类
public class UnsharedConcreteFlyweight extends Flyweight {
public UnsharedConcreteFlyweight(String extrinsic) {
super(extrinsic);
}
@Override
public void operate(int extrinsic) {
System.out.println("不共享的具体Flyweight:" + extrinsic);
}
}
FlyweightFactory类
public class FlyweightFactory {
//定义一个池容器
private static HashMap<String, Flyweight> pool = new HashMap<>();
//享元工厂
public static Flyweight getFlyweight(String extrinsic) {
Flyweight flyweight = null;
if(pool.containsKey(extrinsic)) { //池中有该对象
flyweight = pool.get(extrinsic);
System.out.print("已有 " + extrinsic + " 直接从池中取---->");
} else {
//根据外部状态创建享元对象
flyweight = new ConcreteFlyweight(extrinsic);
//放入池中
pool.put(extrinsic, flyweight);
System.out.print("创建 " + extrinsic + " 并从池中取出---->");
}
return flyweight;
}
}
client 端
public class Client {
public static void main(String[] args) {
Flyweight flyweight1 = FlyweightFactory.getFlyweight("X");
FlyweightFactory.getFlyweight("Y");
FlyweightFactory.getFlyweight("Z");
Flyweight flyweight2 = FlyweightFactory.getFlyweight("X");
Flyweight flyweight3 = new UnsharedConcreteFlyweight("X");
if(flyweight1==flyweight2){
System.out.println("flyweight1与flyweight2是同一个对象");
}
if(flyweight1==flyweight3|| flyweight2==flyweight3){
System.out.println("flyweight1与flyweight3是同一个对象或flyweight2与flyweight3是同一个对象");
}else {
System.out.println("flyweight1与flyweight3不是同一个对象并且flyweight2与flyweight3不是同一个对象");
}
}
}
总结:享元模式其实可以把他作为一个全局变了取看待,这里主要是通过了 hashMap 作为存储,其实还可以用别的集合的方式取存储。都是为了减少对象的创建。