享元模式
如果在某个场景需要很多重复的对象,你会每次都创建一个对象吗?显然重复的创建大量对象是一种很差的体验。这是享元模式就可以帮到我们了,使用享元模式我们可以达到对象共享,避免创建过多的对象,从而提升性能,避免内存泄漏等。
使用环境
- 存在大量相同的对象
- 需要缓冲池的场景
示例
就拿火车售票系统来说,如果有成千上万的人搜索从北京到天津的火车票信息,如果每次请求售票系统都要创建一个从北京到天津的车票结果对象,那么数以万计的人不断请求,那么必然会造成大量对象的创建和销毁,使得GC工作频繁,造成内存抖动,内存高居不下等问题。而从一个地方到另一个地方的车票信息是有限的,我们只需要将它缓存起来,当下一次请求到来时,就可以使用缓存的对象,从而避免了对象的重新创建。这样就将成千上万的对象变成了可选择的有限数量的对象。
首先定义车票展示接口:
public interface TrainTicket {
void showTicketInfo(String seat);
}
它的一个具体实现类是车票信息类,如下:
public class TrainTicketInfo implements TrainTicket{
private String from;//始发站
private String to;//目的地
private String seat;//席别
private int price;//价格
public TrainTicketInfo(String from, String to) {
super();
this.from = from;
this.to = to;
}
@Override
public void showTicketInfo(String seat) {
// TODO Auto-generated method stub
price = new Random().nextInt(200);
System.out.println("购买从"+from+"到"+to+"的"+seat+"火车票的价格是:"+price);
}
}
这个类中包含了起始站,目的站,席别及价格字段,如果不采用缓存的模式则是这种写法:
public class TicketFactory {
public static TrainTicket getTicket(String from,String to){
return new TrainTicketInfo(from,to);
}
}
这种写法每次请求都会创建一个TrainTicketInfo对象,如果在短时间内有百万千万个用户请求北京到天津的火车信息,就会产生百万千万个对象,当对象变得无用时又会被回收,而GC也是十分消耗资源的。这种做法显然不好,可能会导致很多问题。
解决上面这种每次创建对象的形式也简单,就是首次请求时,将new出的对象缓存起来,等下次请求过来时直接使用即可。像这样:
public class TicketFactory {
private static Map<String,TrainTicket> mTicketInfoMap = new HashMap<>();
public static TrainTicket getTicket(String from,String to){
String key = from+"_"+to;
if (mTicketInfoMap.containsKey(key)) {
return mTicketInfoMap.get(key);
}else {
TrainTicket ticket = new TrainTicketInfo(from,to);
mTicketInfoMap.put(key, ticket);
return ticket;
}
}
}
这样无论请求多少次,都会只有一个对象。
享元模式在Android中的应用
享元模式在Android中也有很多应用,如String常量。猜猜下面的代码的输出结果是什么?
String str1 = "123";
String str2 = "12"+"3";
System.out.println(str1 == str2);
答案是true;也就是说str1和str2是同一个对象,因为str2使用了缓存常量池中的str1的对象。享元模式还有很多的应用,如Message通过obtain拿对象其实这里面也是用的享元模式。