享元模式
一、简介
享元模式是对象池的一种实现,它用来尽可能减少内存使用量,适合可能存在大量重复对象的场景,缓存可共享的对象避免创建过多对象。
享元对象中的部分状态是可共享称之为内部状态,内部状态不会随环境变化。不可共享的状态称之为外部状态,会随环境改变而变化。在享元模式中建立一个对象容器它的键是享元对象的内部状态,值是享元对象本身。客户端通过内部状态从享元工厂中获取享元对象,如果有缓存则直接返回缓存否则创建新对象存入容器中然后返回。
定义:使用共享对象可有效地支持大量的细粒度的对象
二、使用场景
- 存在大量相似对象时
- 细粒度的对象都具备较接近的外部状态而且内部状态与环境无关,也就是说对象没有特定身份
- 需要缓冲池的场景
三、简单实现
以查询火车票信息为例,我们在查询某辆火车的车票时会向服务端发送请求,这里的“请求”如果每到一个服务端就创建一个新的使用完成后销毁,这样做会使得大量重复对象创建销毁频繁GC。如果把请求缓存起来则会减少很多内存占用。
public interface Ticket{
void showTicketInfo();
}
public class TrainTicket implements Ticket{
public String from;
public String to;
public String bunk;
public int price;
public TrainTicket(String from, String to) {
this.from = from;
this.to = to;
}
@Override
public void showTicketInfo() {
price=new Random().nextInt(100);
Log.i(TAG, "showTicketInfo: form "+from+" to "+to+" bunk "+bunk+" price "+price);
}
}
public class TicketFactory{
Map<String,Ticket> map=new ConcurrentHashMap<>();
public Ticket getTicket(String form,String to){
String key=form+"-"+to;
if (map.containsKey(key)){
Log.i(TAG, "getTicket: cached");
return map.get(key);
}else {
Log.i(TAG, "getTicket: create");
Ticket ticket=new TrainTicket(form,to);
map.put(key,ticket);
return ticket;
}
}
}
public void Test(){
TicketFactory ticketFactory=new TicketFactory();
Ticket ticket1=ticketFactory.getTicket("北京","天津");
ticket1.showTicketInfo();
Ticket ticket2=ticketFactory.getTicket("北京","天津");
ticket2.showTicketInfo();
Ticket ticket3=ticketFactory.getTicket("北京","天津");
ticket3.showTicketInfo();
}
四、小结
在Android中Handler机制中使用的Message内部就采用了享元模式,Message内部有一个消息缓存池当我们需要一个Message时可以通过Message.obtain来获取一个Message。当缓冲池为空时则会创建Message然后当Message不在使用时回收至缓冲池中。
享元模式可以大大减少对象的创建,降低内存占用,但是它需要分离出外部状态和内部状态,且外部状态具有固话特性。
该模式的优势就是大幅降低内存中对象的数量,但是相对应的它使系统更加复杂。