什么是享元模式?
使用共享对象可有效地支持大量的细粒度对象。
享元模式(FlyWeight pattern)是对象池的一种实现,代表轻量级的思想。适合用在大量重复对象的创建,从而实现内存的优化,提升性能。比如我们要设计个游戏,里边要创建成千上万的士兵角色,我们也许会做一千次new soldier(),但是这样的话对于内存来说会有不必要的消耗,享元模式就很好的解决了这个问题。
享元模式中可共享不随环境改变而改变的对象叫做内部状态,随环境改变而改变的称为外部状态。
享元模式适用场景
系统中存在大量相似对象
对象没有过多的自定义特征
需要缓冲池的系统
享元模式中的角色
FlyWeight:享元对象抽象基类或者接口
ConcreteFlyWeight:具体享元对象
FlyWeightFactory:享元工厂,负责享元对象池和享元对象的创建
享元模式用例
春节回家抢票,每个人都会通过网络向服务器发抢票信息,数以万计的人同时向服务器发出查询余票的信息时,假如服务端每次都创建对象来处理这个请求,也许他会崩溃的更快…优化方法就是使用享元模式把特定的请求缓存在享元对象池中,有了就不必重建,没有再考虑新建。比如1000个用户都在查询北京-郑州的票,使用缓冲池后都从缓冲池中操作,系统处理了这1000个人的查询信息,而新建的只有这一个对象,避免了给内存加额外负担。
UML类图
ITicket接口类:
public interface ITicket{
public void showTicketInfo(String bunk);
}
TrainTicket实现类:
public class TrainTicket implements ITicket {
private String from;
private String to;
private String bunk;
private int price;
public TrainTicket(String from,String to){
this.from = from;
this.to = to;
}
@Override
public void showTicketInfo(String bunk) {
//这里使用不大于300的随机数模仿票价
price = new Random().nextInt(300);
System.out.println("购买从"+from+"到"+to+"的"+bunk+"火车票"+",价格为:"+price);
}
}
TicketFactory类:
public class TicketFactory {
static Map<String,ITicket> mTicketMap = new HashMap<>();
public static ITicket getTicket(String from,String to){
String key = from+"-"+to;
if(mTicketMap.containsKey(key)){
System.out.println("使用缓存--》"+key);
return mTicketMap.get(key);
}else{
System.out.println("新建对象--》"+key);
ITicket ticket= new TrainTicket(from,to);
mTicketMap.put(key, ticket);
return ticket;
}
}
}
主类调用:
public class Test {
public static void main(String[] args) {
ITicket ticket0 = TicketFactory.getTicket("郑州", "北京");
ticket0.showTicketInfo("硬座");
ITicket ticket1 = TicketFactory.getTicket("郑州", "北京");
ticket0.showTicketInfo("上铺");
ITicket ticket2 = TicketFactory.getTicket("郑州", "北京");
ticket0.showTicketInfo("硬卧");
}
}
测试结果:
新建对象--》郑州-北京
购买从郑州到北京的硬座火车票,价格为:209
使用缓存--》郑州-北京
购买从郑州到北京的上铺火车票,价格为:77
使用缓存--》郑州-北京
购买从郑州到北京的硬卧火车票,价格为:272
总结
我们在java中的String定义也是使用到了享元模式,比如
String s = "123";与String s2 = "12"+"3";
//这里如果判断s == s2;是会返回true的结果的,他们引用的是同一内存地址,但是如果使用new来创建就另论了
享元模式的优点:
大大减少程序对象的创建,降低程序内存占用,优化程序性能。
缺点:
享元模式使得系统更为复杂。为了让对象可以共享,需要将一些状态外部化,使得程序的逻辑复杂。
读取外部状态时间效率也有所下降。比如上边订票中,内部状态就是from和to。外部状态是bunk和price,出发地和目的地不变,坐席类型和价格的选择会相应改变。