一、定義
享元模式(Flyweight Pattern)是池技術的重要實作方式其定義如下:使用共享對象可以有效地支援大量的細粒度的對象。
享元模式的定義為我們提出列兩個要求:細粒度對象和共享對象。我們知道配置設定太多的對象到應用程式中将有損程式的性能,同時還容易造成記憶體溢出,那怎麼規避呢 ?就是享元模式提供的共享技術。
要求細粒度對象,則會導緻對象的數量多且屬性都非常相似,為了抽取相同的屬性, 可以将對象内容分為兩個部分:内部狀态(instrinsic)與外部狀态(extrinsic)。
-
内部狀态
内部狀态是對象可共享出來的資訊。存儲在享元對象内部并且不會随着環境改變而改變,他們可以作為一個對象的動态附件資訊, 不直接儲存在對象内部,如一個學生類中的 所屬學校資訊等。
-
外部狀态
外部狀态是對象依賴的一些屬性,是随環境改變而改變的、不可以共享的狀态,如一個使用者類的 建立時間、姓名等。
二、代碼示範
2.1 通用類圖
2.2 角色說明
-
Flyweight–抽象享元角色
簡單說是一個産品的抽象類,同時定義了對象的外部狀态和内部狀态的接口或實作。
-ConcreteFlyweight–具體享元角色
具體的一個産品類,該類中内部狀态處理應該與環境無關,不應該出現一個操作改變了内部狀态,同時修改了外部狀态。
-
unsharedConcreteFlyweight–不可共享的享元角色
不存在外部狀态或線程安全不能夠用共享技術的對象,該對象一般不會出現在享元工廠中。
-
FlyweightFactory–享元工廠
職責非常簡單,就是建構一個池容器,同時提供從池中擷取對象的方法。
2.3 抽象享元角色
抽象享元角色一般為抽象類,在實際項目中,一般是一個實作類,它是描述一類事物的方法。抽象角色中,一般需要把外部狀态和内部狀态定義出來,避免子類的随意擴充。
package com.design.flyweiht.pattern;
/**
* @description 抽象享元對象
* @date: 2019/9/28 17:24
* @version: v 0.1
*/
public abstract class Flyweight {
//内部狀态
private String intrinsic;
//外部狀态
protected final String extrinsic;
public Flyweight(String _extrinsic) {
this.extrinsic = _extrinsic;
}
//定義業務操作
public abstract void operate();
public String getIntrinsic() {
return intrinsic;
}
public void setIntrinsic(String intrinsic) {
this.intrinsic = intrinsic;
}
public String getExtrinsic() {
return extrinsic;
}
}
2.4 具體享元角色
實作自己的業務邏輯,然後接收外部狀态,以便内部業務邏輯對外部狀态的依賴。
package com.design.flyweiht.pattern;
/**
* @description 具體享元對象
* @date: 2019/9/28 17:31
* @version: v 0.1
*/
public class ConcreteFlyweight1 extends Flyweight {
public ConcreteFlyweight1(String _extrinsic) {
super(_extrinsic);
}
@Override
public void operate() {
System.out.println("ConcreteFlyweight1 operate");
}
}
2.5 享元工廠
package com.design.flyweiht.pattern;
import java.util.HashMap;
/**
* @description 享元工廠
* @date: 2019/9/28 17:47
* @version: v 0.1
*/
public class FlyweightFactory {
//定義一個容器
private static HashMap<String, Flyweight> pool = new HashMap<String, Flyweight>();
public static Flyweight getFlyweight(String extriansic) {
//傳回需要的對象
Flyweight flyweight = null;
if (pool.containsKey(extriansic)) {
flyweight = pool.get(extriansic);
System.out.println("FlyweightFactory :" + extriansic + ": come from pool");
} else {
//根據外部狀态建立享元對象
flyweight = new ConcreteFlyweight1(extriansic);
//放到池中
pool.put(extriansic, flyweight);
System.out.println("FlyweightFactory :" + extriansic + ": not come from pool");
}
return flyweight;
}
}
2.6 驗證場景類
package com.design.flyweiht.pattern;
/**
* @description TODO
* @date: 2019/9/28 17:57
* @version: v 0.1
*/
public class Client {
public static void main(String args[]){
String extriansic= "tester";
Flyweight flyweight1 = FlyweightFactory.getFlyweight(extriansic);
flyweight1.operate();
Flyweight flyweight2 = FlyweightFactory.getFlyweight(extriansic);
flyweight2.operate();
}
}
2.7 運作結果
FlyweightFactory :tester: not come from pool
ConcreteFlyweight1 operate
FlyweightFactory :tester: come from pool
ConcreteFlyweight1 operate
三、優點
享元模式是一個非常簡單的模式,可以大大減少應用程式建立的對象,降低程式記憶體占用,增加程式的性能;
四、缺點
由于需要區分内部狀态和外部狀态,而且外部狀态是固化的,可能導緻系統複雜性增加。
五、應用場景
- 系統中存在大量的相似對象。
- 細粒度的對象中外部狀态相似,且内部狀态與環境無關。
- 需要緩沖池的場景。