享元模式
提供了减少对象数量从而改善应用所需的对象结构的方式,运用共享技术有效地支持大量细粒度的对象。
适用于:
底层系统开发,解决性能问题;
系统拥有大量相似对象,需要缓冲池的场景。
优点:
相同对象只要保存一份,这降低了系统中对象的数量,从而降低内存占用
缺点:
关注内/外部状态,关注线程安全问题;
程序的逻辑复杂化。
享元模式中存在以下两种状态:
内部状态,即不会随着环境的改变而改变的可共享部分,可以简单理解为享元对象的属性状态
外部状态,指随环境改变而改变的不可以共享的部分。享元模式的实现要领就是区分应用中的这两种状态,并将外部状态外部化。可以简单理解为方法参数
享元模式的主要角色有如下。
抽象享元角色(Flyweight):是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。
具体享元(Concrete Flyweight)角色:实现抽象享元角色中所规定的接口。
非享元(Unsharable Flyweight)角色:是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中。
享元工厂(Flyweight Factory)角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。
1.制作水果沙拉,创建一个沙拉接口,里面有个添加水果的方法
public interface Salad {
public void add();
}
2.创建具体的实现类水果沙拉 里面有水果的名字和添加的时间两个属性,重新添加方法
public class FruitSalad implements Salad {
private String name;
private LocalDateTime addTime;
public FruitSalad(String name) {
this.name = name;
}
public void setAddTime(LocalDateTime addTime){
this.addTime=addTime;
}
@Override
public void add() {
try {
Thread.sleep(100);
System.out.println("添加"+name+",添加时间为"+addTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3.创建生产水果沙拉的工厂类FruitFactory ,代码关键是通过HashMap存储对象,实现共享。
public class FruitFactory {
private static final HashMap<String,FruitSalad> map=new HashMap();
public static FruitSalad produce(String name){
FruitSalad fruitSalad=map.get(name);
if(fruitSalad==null){
System.out.println("没有"+name+"材料,去冰箱里拿");
fruitSalad=new FruitSalad(name);
map.put(name,fruitSalad);
}
return fruitSalad;
}
}
4.测试输出
public class Test {
private static final String[] FRUIT = {"苹果", "香蕉", "草莓"};
public static void main(String[]args){
IntStream.range(0, 5).forEach((i) -> {
String name = FRUIT[(int) (Math.random() * FRUIT.length)];//随机取数
FruitSalad fruitPie = FruitFactory.produce(name);
fruitPie.setAddTime(LocalDateTime.now());
fruitPie.add();
});
}
}
/*
没有苹果材料,去冰箱里拿
添加苹果,添加时间为2020-08-31T13:14:24.176
没有草莓材料,去冰箱里拿
添加草莓,添加时间为2020-08-31T13:14:24.278
没有香蕉材料,去冰箱里拿
添加香蕉,添加时间为2020-08-31T13:14:24.378
添加香蕉,添加时间为2020-08-31T13:14:24.479
添加草莓,添加时间为2020-08-31T13:14:24.580
*/
从上面的输出看,在5次循环中,只生产了3个材料对象,大概的描述了系统有大量相似对象的时候,需要缓冲池的场景。
JDK中的字符串常量池,数据库连接池等都是用的享元模式。下一篇讲讲组合模式