定義:
- 使用共享對(duì)象可有效地支持大量的細(xì)粒度的對(duì)象。
將對(duì)象信息劃分為: 內(nèi)部狀態(tài)(intrinsic)弃衍、外部狀態(tài)(extrinsic)
內(nèi)部狀態(tài):內(nèi)部狀態(tài)是對(duì)象可以共享出來(lái)的信息,存儲(chǔ)在享元對(duì)象內(nèi)部并且不會(huì)隨環(huán)境改變而改變阻荒,它們可以作為一個(gè)對(duì)象的動(dòng)態(tài)附加信息万牺,不必直接存儲(chǔ)在某個(gè)具體對(duì)象中阳掐,屬于可以共享的部分。
外部狀態(tài):是對(duì)象得以依賴的一個(gè)標(biāo)記武福,是隨環(huán)境改變而改變的解寝、不可以共享的狀態(tài),他是一批對(duì)象的統(tǒng)一標(biāo)識(shí)艘儒,是唯一的一個(gè)索引值聋伦。
public abstract class Flyweight {
private String intrinsic;
public String getIntrinsic() {
return intrinsic;
}
public void setIntrinsic(String intrinsic) {
this.intrinsic = intrinsic;
}
protected final String extrinsic;// final
// 享元角色接受外部的狀態(tài)
public Flyweight(String _extrinsic) {
// TODO Auto-generated constructor stub
this.extrinsic = _extrinsic;
}
// 定義業(yè)務(wù)操作
public abstract void operate();
}
public class ConcreteFlyweightOne extends Flyweight {
public ConcreteFlyweightOne(String _extrinsic) {
super(_extrinsic);
// TODO Auto-generated constructor stub
}
@Override
public void operate() {
// TODO Auto-generated method stub
}
}
public class ConcreteFlyweightTwo extends Flyweight {
public ConcreteFlyweightTwo(String _extrinsic) {
super(_extrinsic);
// TODO Auto-generated constructor stub
}
@Override
public void operate() {
// TODO Auto-generated method stub
}
}
/*
* 創(chuàng)建享元對(duì)象工廠
* */
public class FlyweightFactory {
// 定義對(duì)象池
private static HashMap<String, Flyweight> pool = new HashMap<>();
// 享元工廠
public static Flyweight getFlyweight(String extrinsic) {
Flyweight flyweight = null;
if (pool.containsKey(extrinsic)) {
flyweight = pool.get(extrinsic);
} else {
// 創(chuàng)建享元對(duì)象,并放入pool中
flyweight = new ConcreteFlyweightOne(extrinsic);
pool.put(extrinsic, flyweight);
}
return flyweight;
}
}
優(yōu)點(diǎn)和缺點(diǎn):
- 大大減少應(yīng)用程序創(chuàng)建的對(duì)象界睁,降低程序內(nèi)存的占用觉增,增強(qiáng)程序的性能,但同時(shí)也提高了系統(tǒng)的復(fù)雜性翻斟,需要分離出外部狀態(tài)和內(nèi)部狀態(tài)逾礁,而且外部狀態(tài)具有固化特性,不應(yīng)該隨內(nèi)部狀態(tài)改變而改變访惜,否則導(dǎo)致系統(tǒng)的邏輯混亂嘹履。
使用場(chǎng)景:
- 系統(tǒng)存在大量的相似對(duì)象
- 細(xì)粒度的對(duì)象都具備接近的外部狀態(tài),而且內(nèi)部狀態(tài)與環(huán)境無(wú)關(guān)债热,對(duì)象沒有特定身份
- 需要緩沖池的場(chǎng)景
享元模式拓展
- 線程安全的問(wèn)題:我們?cè)谑褂孟碓J降臅r(shí)候砾嫉,對(duì)象池中的享元對(duì)象盡量多,多到足夠滿足業(yè)務(wù)為止
- 性能平衡:盡量使用java基本類型作為外部狀態(tài)(如果把一個(gè)對(duì)象作為Map類的鍵值窒篱,一定要確保重寫了equals和hashCode方法焕刮,否則會(huì)出現(xiàn)搜索失敗的情況)
最佳實(shí)踐:
public class Test {// api 中的享元模式
public static void main(String[] args) {
String str1 = "和諧";
String str2 = "社會(huì)";
String str3 = "和諧社會(huì)";
String str4;
str4 = str1 + str2;
System.out.println(str4 == str3);
str4 = (str1 + str2).intern();
System.out.println(str4 == str3);
}
}
>false
>true
雖然可以使用享元模式來(lái)實(shí)現(xiàn)對(duì)象池舶沿,但是二者還是有比較大的區(qū)別,對(duì)象池著重在對(duì)象的復(fù)用上配并,對(duì)象池中的每個(gè)對(duì)象都是可替換的括荡,從對(duì)象池中取出的對(duì)象a、對(duì)象b對(duì)客戶端來(lái)說(shuō)是完全相同的溉旋,主要解決復(fù)用畸冲,而享元模式主要解決的是對(duì)象的共享問(wèn)題,如何建立多個(gè)可共享的細(xì)粒度對(duì)象則是其關(guān)注的重點(diǎn)观腊。