一、介绍,定义
又称 FlyWeight,代表轻量级的意思,结构型设计模式。
享元模式是对象池的一种实现。类似于线程池,线程池可以避免不停的创建和销毁多个对象,消耗性能。享元模式也是为了减少内存的使用,避免出现大量重复的创建销毁对象的场景。
享元模式用在一批相同或相似的对象上,这些对象有可以共享的内部状态和各自不同的外部状态。
享元模式中会有一个工厂,工厂维护着一个容器,容器以键值对的方式存储,键是对象的内部状态,也就是共享的部分,值就是对象本身。客户端从这个工厂获取对象,如果容器中存在这个对象就直接返回,不存在再创建新的对象并存入容器,避免了大量重复创建对象。
使用共享对象有效的支持大量的细粒度对象的复用。
二、使用场景
系统中存在大量的 相似对象。
细粒度的对象都具备较接近的外部状态,且内部状态与环境无关,即对象没有特定身份。
需要 缓冲池 的场景。
三、UML类图
四、简单实现
例1. 过年回家买火车票,无数人在客户端上订票 (有多次购票、刷票的情况),即不断向服务端发送请求。
而每次查询,服务器必须做出回应,具体地,用户查询输入出发地和目的地,查询结构返回值只有一趟列车的车票。而数以万计的人有同样需求,即不间断请求数据,每次重新创建一个查询的车票结果,即造成大量重复对象创建、销毁,使得服务器压力加重。
享元模式正好适合解决该情形的问题,例如 A 到 B 地的车辆是有限的,车上铺位分硬卧、软卧和坐票三种,将这些可公用的对象缓存起来。用户查询时优先使用缓存,反之则重新创建。
public interface Ticket {
public void showTicketInfo(String bunk);
}// 火车票
public class TrainTicket implements Ticket {
public String from; // 始发地
public String to; // 目的地
public String bunk; // 铺位
TrainTicket(String from, String to) {
this.from = from;
this.to = to;
}
@Override
public void showTicketInfo(String bunk) {
price = new Random().nextInt(300);
System.out.println("From:" + from+ "To:" + to + "Bunk:" + bunk + "Price:" + price);
}
}
public class TicketFactory {
static Map<String, Ticket> sTicketMap = new ConcurrentHashMap<String, Ticket>();
public static Ticket getTicket(String from, String to) {
String key = from + "-" + to;
if( sTicketMap.containsKey(key) ) { // 使用缓存
return sTicketMap.get(key);
} else { // 创建对象
Ticket ticket = new TrainTicket(from, to);
sTicketMap.put(key, ticket);
return ticket;
}
}
}
我们知道 Java 中 String 是存在于常量池中,即一个 String 被定义之后它就被缓存到了常量池中,当其他地方使用同样的字符串,则直接使用缓存,而非创建。
五、模式的优缺点:
享元模式的优缺点
优点 - 大幅度地降低内存中对象的数量。
缺点-1) 为了使对象可共享,需将一些状态外部化,使程序的逻辑复杂化
- 将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。