原文地址 http://blog.csdn.net/qq_25806863/article/details/69952037
享元模式是對象池的一種實現。類似於線程池,線程池可以避免不停的創建和銷燬多個對象,消耗性能。享元模式也是爲了減少內存的使用,避免出現大量重複的創建銷燬對象的場景。
享元模式用在一批相同或相似的對象上,這些對象有可以共享的內部狀態和各自不同的外部狀態。
享元模式中會有一個工廠,工廠維護着一個容器,容器以鍵值對的方式存儲,鍵是對象的內部狀態,也就是共享的部分,值就是對象本身。
客戶端從這個工廠獲取對象,如果容器中存在這個對象就直接返回,不存在再創建新的對象並存入容器,避免了大量重複創建對象。
定義
使用共享對象有效的支持大量的細粒度對象的複用。
使用場景
- 系統存在大量相似或相同的對象。
- 這些對象有較接近的外部狀態。
- 需要緩衝池時。
UML
- Flyweight:享元對象抽象類或接口。
- ConcreteFlyweight:具體的享元對象
- FlyweightFactory:享元工廠,管理對象池和創建享元對象。
簡單實現
以查詢火車票價爲例。假如每張車票信息都是一個對象,當有很多人在查詢一個車票信息時,系統就會重複創建這個車票信息返回給每個人,這樣會不停的創建和銷燬對象,引發頻繁的GC,影響效率。
車票是有限的,結構是一樣的,內容是相似的,這裏簡化一下,假設車票上只有始發地,到達地,座位類型,票價四個內容。所以,如果緩存下來車票的話,就不管有多少人查詢,都不會頻繁的創建銷燬對象了。
把始發地和到達地看做是內部可以共享的狀態,當做緩存的鍵,整個車票對象爲值。
抽象的車票,提供一個方法展示車票信息,傳入信息是要查詢的座位類型:
public interface Ticket {
void showInfo(String type);
}
具體的車票,這裏每次查詢的事隨機生成票價:
public class ConcreteTicket implements Ticket {
private String from;
private String to;
private int price;
private String type;
public ConcreteTicket(String from, String to) {
this.from = from;
this.to = to;
}
@Override
public void showInfo(String type) {
price = new Random().nextInt(500);
this.type=type;
System.out.println("從"+from+"到"+to+"的"+this.type+"票價是"+price);
}
}
車票工廠:
public class TicketFactory {
private static Map<String,Ticket> tickets = new HashMap<>();
public static Ticket getTicket(String from,String to){
String key = from+to;
if (tickets.containsKey(key)){
System.out.println("從緩存中獲取");
return tickets.get(key);
}else {
System.out.println("新建對象");
Ticket ticket = new ConcreteTicket(from,to);
tickets.put(key,ticket);
return ticket;
}
}
}
客戶端調用:
public class Client {
public static void main(String[] args) {
TicketFactory.getTicket("A","B").showInfo("硬座");
TicketFactory.getTicket("A","B").showInfo("硬臥");
TicketFactory.getTicket("C","B").showInfo("硬臥");
}
}
輸出:
總結
享元模式的核心就在享元工廠,因爲享元對象有可共享的內部狀態部分和不可共享的外部狀態部分,因此,內部可共享的就交給工廠去維護處理了,而外部可變的就可以交給客戶端去實現。
優點
- 大大減少系統創建的對象,降低內存總對象的數量,降低程序佔用的內存,增強系統的性能。
缺點
- 將對象分爲內部狀態和外部狀態兩部分,導致系統變複雜,邏輯也更復雜。
- 將享元對象的狀態外部化,而讀取外部狀態使得運行時間稍微變長。