Java 設計模式03 享元模式
1 享元模式 簡介
Use sharing to support large numbers of fine-grained objects efficiently.
使用共享對象可有效地支持大量的細粒度的對象。
享元模式(Flyweight Pattern):又稱爲 輕量級模式,是一種軟件設計常用的對象結構型模式。它使用共享物件,用來儘可能減少內存使用量以及分享資訊給儘可能多的相似物件;它適合用於只是因重複而導致使用無法令人接受的大量內存的大量物件。通常物件中的部分狀態是可以分享。常見做法是把它們放在外部數據結構,當需要使用時再將它們傳遞給享元。
享元模式(Flyweight)又稱爲 輕量級模式,它是一種對象結構型模式。
面向對象技術可以很好地解決一些靈活性或可擴展性問題,但在很多情況下需要在系統中增加類和對象的個數。當對象數量太多時,將導致運行代價過高,帶來性能下降等問題。享元模式 正是爲解決這一類問題而誕生的。
享元模式 是對象池的一種實現。類似於線程池,線程池可以避免不停的創建和銷燬多個對象,消耗性能。享元模式 也是爲了減少內存的使用,避免出現大量重複的創建銷燬對象的場景。
享元模式 的宗旨是共享細粒度對象,將多個對同一對象的訪問集中起來,不必爲每個訪問者創建一個單獨的對象,以此來降低內存的消耗。
享元模式 把一個對象的狀態分成內部狀態和外部狀態,內部狀態即是不變的,外部狀態是變化的;然後通過共享不變的部分,達到減少對象數量並節約內存的目的。
享元模式 本質:緩存共享對象,降低內存消耗。
主要解決
當系統中多處需要同一組信息時,可以把這些信息封裝到一個對象中,然後對該對象進行緩存,這樣,一個對象就可以提供給多處需要使用的地方,避免大量同一對象的多次創建,消耗大量內存空間。
享元模式 其實就是 工廠模式 的一個改進機制,享元模式 同樣要求創建一個或一組對象,並且就是通過工廠方法生成對象的,只不過 享元模式 中爲工廠方法增加了緩存這一功能。
1.1 享元模式 優點
- 享元模式 可以極大減少內存中對象的數量,使得相同對象或相似對象在內存中只保存一份,降低內存佔用,增強程序的性能;
- 享元模式 的外部狀態相對獨立,而且不會影響其內部狀態,從而使得享元對象可以在不同的環境中被共享;
1.2 享元模式 缺點
- 享元模式 使得系統更加複雜,需要分離出內部狀態和外部狀態,這使得程序的邏輯複雜化;
- 爲了使對象可以共享,享元模式 需要將享元對象的狀態外部化,而且外部狀態必須具備固化特性,不應該隨內部狀態改變而改變,否則會導致系統的邏輯混亂;
1.3 享元模式 使用場景
- 系統中存在大量的相似對象;
- 細粒度的對象都具備較接近的外部狀態,而且內部狀態與環境無關,也就是說對象沒有特定身份;
- 需要緩衝池的場景;
2 享元模式 UML 圖
角色 | 名稱 | 功能 |
---|---|---|
享元工廠類 | FlyweightFactory | |
抽象享元類 | Flyweight | |
具體享元類 | ConcreteFlyweight | |
非共享具體享元類 | UnsharedConcreteFlyweight |
3 享元模式 實現
3.1 享元工廠類
package com.xu.modle.modle1;
import java.util.HashMap;
/**
* 享元工廠類
* @author hyacinth
* @date 2019年12月4日12:10:09
*
*/
public class FlyweightFactory {
/**
* 享元對象 容器池
* @date 2019年12月4日12:10:09
*/
private static HashMap<String, Flyweight> pool = new HashMap<>();
/**
* 獲取 享元對象
* @param extrinsic 享元對象 內部狀態 描述
* @return Flyweight
* @date 2019年12月4日12:10:09
*/
public static Flyweight getFlyweight(String extrinsic) {
Flyweight flyweight = null;
if(pool.containsKey(extrinsic)) {//如果對象存 則在池中取該享元對象
flyweight = pool.get(extrinsic);
System.out.print("取出享元對象: " + extrinsic);
} else {//如果對象不存在 則根據外部狀態創建享元對象
flyweight = new ConcreteFlyweight(extrinsic);
pool.put(extrinsic, flyweight);//放入池中
System.out.print("創建享元對象 :" + extrinsic);
}
return flyweight;
}
}
3.2 抽象享元類
package com.xu.modle.modle1;
/**
* 抽象享元類
* @author hyacinth
* @date 2019年12月4日12:10:09
*
*/
public abstract class Flyweight {
/**
* 抽象享元類 構造方法 設置 外部狀態
* @param extrinsic
* @date 2019年12月4日12:10:09
*/
public Flyweight(String extrinsic) {
this.extrinsic = extrinsic;
}
/**
* 享元對象 內部狀態
* @date 2019年12月4日12:10:09
*/
public String intrinsic;
/**
* 享元對象 外部狀態
* @date 2019年12月4日12:10:09
*/
protected final String extrinsic;
/**
* 具體功能實現
* @param extrinsic
* @date 2019年12月4日12:10:09
*/
public abstract void operate(int extrinsic);
/**
* 設置 內部狀態
* @return
* @date 2019年12月4日12:10:09
*/
public String getIntrinsic() {
return intrinsic;
}
/**
* 獲取 內部狀態
* @return
* @date 2019年12月4日12:10:09
*/
public void setIntrinsic(String intrinsic) {
this.intrinsic = intrinsic;
}
}
3.3 具體享元類
package com.xu.modle.modle1;
/**
* 具體享元類
* @author hyacinth
* @date 2019年12月4日12:10:09
*
*/
public class ConcreteFlyweight extends Flyweight {
/**
* 具體享元類 構造方法 設置享元類 外部狀態
* @param extrinsic
* @date 2019年12月4日12:10:09
*/
public ConcreteFlyweight(String extrinsic) {
super(extrinsic);
}
@Override
public void operate(int extrinsic) {
System.out.println("具體Flyweight:-->" +super.extrinsic+"\t"+ extrinsic);
}
}
3.4 非共享具體享元類
package com.xu.modle.modle1;
/**
* 非共享具體享元類
* @author hyacinth
* @date 2019年12月4日12:10:09
*
*/
public class UnsharedConcreteFlyweight extends Flyweight {
/**
* 非共享具體享元類 構造方法 設置享元類 外部狀態
* @param extrinsic
* @date 2019年12月4日12:10:09
*/
public UnsharedConcreteFlyweight(String extrinsic) {
super(extrinsic);
}
@Override
public void operate(int extrinsic) {
System.out.println("非共享的具體Flyweight:-->" +super.extrinsic+"\t"+ extrinsic);
}
}
3.5 測試類
package com.xu.modle.modle1;
public class Client {
public static void main(String[] args) {
int extrinsic = 22;
Flyweight X = FlyweightFactory.getFlyweight("X");
X.operate(extrinsic++);
Flyweight Y = FlyweightFactory.getFlyweight("Y");
Y.operate(extrinsic++);
Flyweight Z = FlyweightFactory.getFlyweight("Z");
Z.operate(extrinsic++);
Flyweight ReX = FlyweightFactory.getFlyweight("X");
ReX.operate(extrinsic++);
Flyweight UX = new UnsharedConcreteFlyweight("X");
UX.operate(extrinsic++);
}
}