系列文章
【設(shè)計(jì)模式】七大設(shè)計(jì)原則
【設(shè)計(jì)模式】第一章:?jiǎn)卫J?br>【設(shè)計(jì)模式】第二章:工廠模式
【設(shè)計(jì)模式】第三章:建造者模式
【設(shè)計(jì)模式】第四章:原型模式
【設(shè)計(jì)模式】第五章:適配器模式
【設(shè)計(jì)模式】第六章:裝飾器模式
【設(shè)計(jì)模式】第七章:代理模式
【設(shè)計(jì)模式】第八章:橋接模式
【設(shè)計(jì)模式】第九章:外觀模式 / 門(mén)面模式
【設(shè)計(jì)模式】第十章:組合模式
【設(shè)計(jì)模式】第十一章:享元模式
【設(shè)計(jì)模式】第十二章:觀察者模式
【設(shè)計(jì)模式】第十三章:模板方法模式
【設(shè)計(jì)模式】第十四章:策略模式
【設(shè)計(jì)模式】第十五章:責(zé)任鏈模式
【設(shè)計(jì)模式】第十六章:迭代器模式
【設(shè)計(jì)模式】第十七章:狀態(tài)模式
【設(shè)計(jì)模式】第十八章:備忘錄模式
【設(shè)計(jì)模式】第十九章:訪問(wèn)者模式
【設(shè)計(jì)模式】第二十章:解釋器模式
【設(shè)計(jì)模式】第二十一章:命令模式
【設(shè)計(jì)模式】第二十二章:中介者模式
一、定義
摘自百度百科: 它使用共享物件,用來(lái)盡可能減少內(nèi)存使用量以及分享資訊給盡可能多的相似物件;它適合用于只是因重復(fù)而導(dǎo)致使用無(wú)法令人接受的大量?jī)?nèi)存的大量物件。通常物件中的部分狀態(tài)是可以分享。常見(jiàn)做法是把它們放在外部數(shù)據(jù)結(jié)構(gòu),當(dāng)需要使用時(shí)再將它們傳遞給享元。
二、角色分類(lèi)
抽象享元類(lèi)(Flyweight)
通常是一個(gè)接口或抽象類(lèi),其聲明了具體享元類(lèi)的公共方法,這些方法可以向外界提供享元對(duì)象的內(nèi)部數(shù)據(jù)或內(nèi)部狀態(tài),同時(shí)也可以通過(guò)這些方法來(lái)設(shè)置外部數(shù)據(jù)或外部狀態(tài)
具體享元類(lèi)(Concrete Flyweight)
它實(shí)現(xiàn)了抽象享元類(lèi),它的實(shí)例被稱(chēng)為享元對(duì)象;在具體享元類(lèi)內(nèi)部狀態(tài)提供了存儲(chǔ)空間。通常我們可以結(jié)合單例模式來(lái)設(shè)計(jì)具體享元類(lèi),為每一個(gè)具體享元類(lèi)提供唯一的享元對(duì)象。
非共享具體享元類(lèi)(Unshared Concrete Flyweight)
不能被共享的子類(lèi)可被設(shè)計(jì)為非共享具體享元類(lèi),當(dāng)需要一個(gè)非共享具體享元類(lèi)的對(duì)象時(shí)可以直接通過(guò)實(shí)例化創(chuàng)建
享元工廠類(lèi)(Flyweight Factory)
該類(lèi)主要用于創(chuàng)建和管理享元對(duì)象,它針對(duì)抽象享元類(lèi)變成,將各種類(lèi)型的具體享元對(duì)象存儲(chǔ)在一個(gè)享元池中,享元池一般設(shè)計(jì)為一個(gè)存儲(chǔ)鍵值對(duì)的集合(也可以是其他類(lèi)型的集合),可以結(jié)合工廠模式進(jìn)行設(shè)計(jì)
客戶(hù)角色(Client)
具體調(diào)用方法的角色
三、實(shí)現(xiàn)方式
UML圖
單純享元模式
抽象享元類(lèi)(Flyweight)
public interface Flyweight {
public void operate(String type);
}
具體享元類(lèi)(Concrete Flyweight)和非共享具體享元類(lèi)(Unshared Concrete Flyweight)
public class CharacterFlyWeight implements Flyweight {
// 內(nèi)部狀態(tài)是不變的,外部狀態(tài)是變化的
// 然后通過(guò)共享不變的部分,達(dá)到減少對(duì)象數(shù)量并節(jié)約內(nèi)存的目的
private String name;
/**
* 外部狀態(tài)(非享元)
* @param name
*/
public CharacterFlyWeight(String name) {
this.name = name;
}
/**
* 具體享元+非享元結(jié)合
* @param type
*/
@Override
public void operate(String type) {
System.out.println("姓名 = " + name);
System.out.println("屬性 = " + type);
}
}
享元工廠(Flyweight Factory)
public class FlyweightFactory {
// 由工廠方法產(chǎn)生所需要的享元對(duì)象
private Map<String, Flyweight> characterPool = new HashMap<>();
public Flyweight factory(String user) {
// 先從緩存中查找對(duì)象
Flyweight flyweight = characterPool.get(user);
if (null == flyweight) {
// 如果對(duì)象不存在則創(chuàng)建一個(gè)新對(duì)象
flyweight = new CharacterFlyWeight(user);
// 將新對(duì)象添加到緩存中
characterPool.put(user, flyweight);
}
return flyweight;
}
}
客戶(hù)角色(Client)
public class Client {
public static void main(String[] args) {
FlyweightFactory factory = new FlyweightFactory();
Flyweight flyweightA = factory.factory("小A");
flyweightA.operate("文靜");
Flyweight flyweightB = factory.factory("小B");
flyweightB.operate("靦腆");
Flyweight flyweightC = factory.factory("小A");
flyweightC.operate("活潑");
System.out.println(flyweightA == flyweightC); //true
}
}
運(yùn)行結(jié)果
姓名 = 小A
屬性 = 文靜
姓名 = 小B
屬性 = 靦腆
姓名 = 小A
屬性 = 活潑
true
復(fù)合享元模式
抽象享元角色(Flyweight)
public interface Flyweight {
public void operate(String type);
}
具體享元角色(Concrete Flyweight)和非共享具體享元角色(Unshared Concrete Flyweight)
public class CharacterFlyweight implements Flyweight {
// 內(nèi)部狀態(tài)是不變的,外部狀態(tài)變化
// 通過(guò)共享不變的部分,達(dá)到減少對(duì)象數(shù)量并節(jié)約內(nèi)存的目的
private String name;
/**
* 外部狀態(tài)(非享元)
* @param name
*/
public CharacterFlyweight(String name) {
this.name = name;
}
/**
* 具體享元和非享元結(jié)合
* @param type
*/
@Override
public void operate(String type) {
System.out.println("姓名 = " + name);
System.out.println("屬性 = " + type);
}
}
復(fù)合享元角色(Composite Concrete Flyweight)
public class CharacterCompositeFlyweight implements Flyweight {
private Map<String, Flyweight> files = new HashMap<>();
/**
* 增加一個(gè)新的單純享元對(duì)象到集合里
*/
public void add(String key, Flyweight flyweight) {
files.put(key, flyweight);
}
/**
* 外部狀態(tài)作為參數(shù)傳入到方法中
*/
@Override
public void operate(String type) {
Flyweight flyweight;
for (String key : files.keySet()) {
flyweight = files.get(key);
flyweight.operate(type);
}
}
}
享元工廠角色(Flyweight Factory)
public class FlyweightFactory {
private Map<String, Flyweight> characterPool = new HashMap<>();
/**
* 復(fù)合工廠方法
* 一種用于提供單純享元對(duì)象,另一種提供復(fù)合享元對(duì)象
*/
public Flyweight factory(List<String> compositeState) {
CharacterCompositeFlyweight compositeFlyweight = new CharacterCompositeFlyweight();
compositeState.forEach(any -> compositeFlyweight.add(any, this.factory(any)));
return compositeFlyweight;
}
/**
* 單純工廠方法
* 提供所需要的享元對(duì)象
*/
public Flyweight factory(String user) {
// 先從緩存中查找對(duì)象
Flyweight flyweight = characterPool.get(user);
if (null == flyweight) {
// 如果對(duì)象不存在則創(chuàng)建一個(gè)新對(duì)象
flyweight = new CharacterFlyweight(user);
// 將新對(duì)象添加到緩存中
characterPool.put(user, flyweight);
}
return flyweight;
}
}
客戶(hù)角色(Client)
public class Client {
public static void main(String[] args) {
List<String> compositeState = new ArrayList<String>();
compositeState.add("小A");
compositeState.add("小B");
compositeState.add("小C");
compositeState.add("小B");
compositeState.add("小A");
FlyweightFactory flyFactory = new FlyweightFactory();
Flyweight compositeFly1 = flyFactory.factory(compositeState);
Flyweight compositeFly2 = flyFactory.factory(compositeState);
compositeFly1.operate("夢(mèng)游中...");
System.out.println("---------------------------------");
System.out.println("復(fù)合享元模式是否可以共享對(duì)象:" + (compositeFly1 == compositeFly2)); //false
String user = "小A";
Flyweight fly1 = flyFactory.factory(user);
Flyweight fly2 = flyFactory.factory(user);
System.out.println("單純享元模式是否可以共享對(duì)象:" + (fly1 == fly2)); //true
}
}
運(yùn)行結(jié)果
姓名 = 小B
屬性 = 夢(mèng)游中...
姓名 = 小A
屬性 = 夢(mèng)游中...
姓名 = 小C
屬性 = 夢(mèng)游中...
---------------------------------
復(fù)合享元模式是否可以共享對(duì)象:false
單純享元模式是否可以共享對(duì)象:true
四、應(yīng)用場(chǎng)景
以下部分內(nèi)容摘自菜鳥(niǎo)教程
意圖: 運(yùn)用共享技術(shù)有效地支持大量細(xì)粒度的對(duì)象。
主要解決: 在有大量對(duì)象時(shí),有可能會(huì)造成內(nèi)存溢出,我們把其中共同的部分抽象出來(lái),如果有相同的業(yè)務(wù)請(qǐng)求,直接返回在內(nèi)存中已有的對(duì)象,避免重新創(chuàng)建。
何時(shí)使用:
- 系統(tǒng)中有大量對(duì)象。
- 這些對(duì)象消耗大量?jī)?nèi)存。
- 這些對(duì)象的狀態(tài)大部分可以外部化。
- 這些對(duì)象可以按照內(nèi)蘊(yùn)狀態(tài)分為很多組,當(dāng)把外蘊(yùn)對(duì)象從對(duì)象中剔除出來(lái)時(shí),每一組對(duì)象都可以用一個(gè)對(duì)象來(lái)代替。
- 系統(tǒng)不依賴(lài)于這些對(duì)象身份,這些對(duì)象是不可分辨的。
如何解決: 用唯一標(biāo)識(shí)碼判斷,如果在內(nèi)存中有,則返回這個(gè)唯一標(biāo)識(shí)碼所標(biāo)識(shí)的對(duì)象。
關(guān)鍵代碼: 用 HashMap 存儲(chǔ)這些對(duì)象。
應(yīng)用實(shí)例:
- JAVA 中的 String,如果有則返回,如果沒(méi)有則創(chuàng)建一個(gè)字符串保存在字符串緩存池里面。
- 數(shù)據(jù)庫(kù)的連接池。
使用場(chǎng)景:
- 系統(tǒng)有大量相似對(duì)象。
- 需要緩沖池的場(chǎng)景。
注意事項(xiàng):
- 注意劃分外部狀態(tài)和內(nèi)部狀態(tài),否則可能會(huì)引起線程安全問(wèn)題。
- 這些類(lèi)必須有一個(gè)工廠對(duì)象加以控制。
五、優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
大大減少對(duì)象的創(chuàng)建,降低系統(tǒng)的內(nèi)存,使效率提高。
缺點(diǎn)
提高了系統(tǒng)的復(fù)雜度,需要分離出外部狀態(tài)和內(nèi)部狀態(tài),而且外部狀態(tài)具有固有化的性質(zhì),不應(yīng)該隨著內(nèi)部狀態(tài)的變化而變化,否則會(huì)造成系統(tǒng)的混亂。
推薦
關(guān)注博客和公眾號(hào)獲取最新文章文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-536902.html
Bummon’s Blog | Bummon’s Home | 公眾號(hào)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-536902.html
到了這里,關(guān)于【設(shè)計(jì)模式】第十一章:享元模式詳解及應(yīng)用案例的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!