計(jì)模式?享元(Flyweight)設(shè)計(jì)模式)
文章目錄一.什么是享元設(shè)計(jì)模式二.享元模式的特點(diǎn)三.享元模式的結(jié)構(gòu)四.享元模式的優(yōu)缺點(diǎn)五.享元模式的 C 實(shí)現(xiàn)六.享元模式的 JAVA 實(shí)現(xiàn)七.代碼解析八.總結(jié)類圖享元設(shè)計(jì)模式類圖一.什么是享元設(shè)計(jì)模式享元Flyweight設(shè)計(jì)模式是一種結(jié)構(gòu)型設(shè)計(jì)模式通過(guò)共享對(duì)象來(lái)減少內(nèi)存占用和對(duì)象創(chuàng)建開銷。它通過(guò)將對(duì)象的可共享部分內(nèi)部狀態(tài)與不可共享部分外部狀態(tài)分離減少重復(fù)對(duì)象的數(shù)量從而節(jié)省內(nèi)存。享元模式的核心思想是共享對(duì)象狀態(tài)在需要大量相似對(duì)象時(shí)僅存儲(chǔ)少量可復(fù)用的對(duì)象其他狀態(tài)通過(guò)外部管理。二.享元模式的特點(diǎn)共享性通過(guò)共享相同狀態(tài)的對(duì)象降低內(nèi)存占用。分離狀態(tài)內(nèi)部狀態(tài)對(duì)象內(nèi)部不變的部分可以被多個(gè)對(duì)象共享存放在享元對(duì)象內(nèi)部。外部狀態(tài)對(duì)象動(dòng)態(tài)變化的部分不能共享由客戶端負(fù)責(zé)維護(hù)、傳入。核心區(qū)分內(nèi)部狀態(tài)不隨場(chǎng)景改變外部狀態(tài)隨使用場(chǎng)景變化不保存到享元對(duì)象。三.享元模式的結(jié)構(gòu)Flyweight抽象享元類定義對(duì)象共享的接口通常是輕量化接口操作接收外部狀態(tài)作為參數(shù)。ConcreteFlyweight具體享元類實(shí)現(xiàn)抽象享元類存儲(chǔ)對(duì)象的內(nèi)部狀態(tài)可共享。UnsharedConcreteFlyweight非共享享元類不需要共享的對(duì)象即使細(xì)粒度也不做共享。FlyweightFactory享元工廠類維護(hù)享元對(duì)象池哈希容器管理享元對(duì)象的創(chuàng)建與復(fù)用。Client客戶端維護(hù)外部狀態(tài)調(diào)用享元對(duì)象把外部狀態(tài)傳入享元接口。四.享元模式的優(yōu)缺點(diǎn)優(yōu)點(diǎn)減少大量重復(fù)對(duì)象創(chuàng)建顯著節(jié)省內(nèi)存。提高性能尤其系統(tǒng)存在大量細(xì)粒度相似對(duì)象時(shí)。缺點(diǎn)增加系統(tǒng)復(fù)雜度需要區(qū)分、分離內(nèi)部狀態(tài)與外部狀態(tài)。外部狀態(tài)由客戶端維護(hù)必須保證外部狀態(tài)傳入正確否則業(yè)務(wù)邏輯出錯(cuò)。五.享元模式的 C 實(shí)現(xiàn)場(chǎng)景森林中大量樹木樹種名稱、顏色、紋理 內(nèi)部狀態(tài)享元共享每棵樹的坐標(biāo)x、y 外部狀態(tài)客戶端維護(hù)。相同樹種只創(chuàng)建一份TreeType對(duì)象多棵樹持有這個(gè)共享對(duì)象各自保存自己的位置。#includeiostream#includeunordered_map#includestring#includememoryusingnamespacestd;// Flyweight抽象享元類classTreeType{protected:string name;// 內(nèi)部狀態(tài)樹名稱string color;// 內(nèi)部狀態(tài)顏色string texture;// 內(nèi)部狀態(tài)紋理public:TreeType(conststringname,conststringcolor,conststringtexture):name(name),color(color),texture(texture){}// 操作接口x,y為傳入的外部狀態(tài)virtualvoidDisplay(intx,inty)const0;virtual~TreeType()default;};// ConcreteFlyweight具體享元類存儲(chǔ)內(nèi)部狀態(tài)classConcreteTreeType:publicTreeType{public:ConcreteTreeType(conststringname,conststringcolor,conststringtexture):TreeType(name,color,texture){}voidDisplay(intx,inty)constoverride{coutTree [Type: name, Color: color, Texture: texture] at (x, y)endl;}};// FlyweightFactory享元工廠維護(hù)享元池classTreeFactory{private:unordered_mapstring,shared_ptrTreeTypetreeTypes;// 對(duì)象池public:shared_ptrTreeTypeGetTreeType(conststringname,conststringcolor,conststringtexture){// 拼接key根據(jù)內(nèi)部狀態(tài)生成唯一鍵string keyname_color_texture;if(treeTypes.find(key)treeTypes.end()){// 池中沒(méi)有則新建享元對(duì)象放入池treeTypes[key]make_sharedConcreteTreeType(name,color,texture);coutCreated new TreeType: keyendl;}returntreeTypes[key];// 返回共享對(duì)象}};// 客戶端輔助類 Tree持有享元對(duì)象保存外部狀態(tài) x,yclassTree{private:shared_ptrTreeTypetype;// 共享享元對(duì)象intx,y;// 外部狀態(tài)坐標(biāo)每個(gè)樹自己獨(dú)有public:Tree(intx,inty,shared_ptrTreeTypetype):x(x),y(y),type(type){}voidDisplay()const{type-Display(x,y);// 將外部狀態(tài)傳給享元對(duì)象執(zhí)行}};// 主函數(shù)客戶端intmain(){TreeFactory factory;// 創(chuàng)建多棵樹部分樹種會(huì)復(fù)用享元對(duì)象shared_ptrTreetree1make_sharedTree(10,20,factory.GetTreeType(Oak,Green,Smooth));shared_ptrTreetree2make_sharedTree(15,25,factory.GetTreeType(Pine,Dark Green,Rough));shared_ptrTreetree3make_sharedTree(10,20,factory.GetTreeType(Oak,Green,Smooth));// 復(fù)用Oak對(duì)象// 打印樹信息tree1-Display();tree2-Display();tree3-Display();return0;}C運(yùn)行輸出Created new TreeType: Oak_Green_Smooth Created new TreeType: Pine_Dark Green_Rough Tree [Type: Oak, Color: Green, Texture: Smooth] at (10, 20) Tree [Type: Pine, Color: Dark Green, Texture: Rough] at (15, 25) Tree [Type: Oak, Color: Green, Texture: Smooth] at (10, 20)可以看到Oak只創(chuàng)建1次tree1、tree3共用同一個(gè)享元對(duì)象實(shí)例。六.享元模式的 Java 實(shí)現(xiàn)importjava.util.HashMap;importjava.util.Map;// Flyweight抽象享元類abstractclassTreeType{protectedStringname;protectedStringcolor;protectedStringtexture;publicTreeType(Stringname,Stringcolor,Stringtexture){this.namename;this.colorcolor;this.texturetexture;}publicabstractvoiddisplay(intx,inty);}// ConcreteFlyweight 具體享元classConcreteTreeTypeextendsTreeType{publicConcreteTreeType(Stringname,Stringcolor,Stringtexture){super(name,color,texture);}Overridepublicvoiddisplay(intx,inty){System.out.println(Tree [Type: name, Color: color, Texture: texture] at (x, y));}}// FlyweightFactory享元工廠classTreeFactory{privateMapString,TreeTypetreeTypesnewHashMap();publicTreeTypegetTreeType(Stringname,Stringcolor,Stringtexture){Stringkeyname_color_texture;if(!treeTypes.containsKey(key)){treeTypes.put(key,newConcreteTreeType(name,color,texture));System.out.println(Created new TreeType: key);}returntreeTypes.get(key);}}// 客戶端輔助類持有外部狀態(tài)classTree{privateTreeTypetype;privateintx,y;publicTree(intx,inty,TreeTypetype){this.xx;this.yy;this.typetype;}publicvoiddisplay(){type.display(x,y);}}// 客戶端publicclassFlyweightPatternDemo{publicstaticvoidmain(String[]args){TreeFactoryfactorynewTreeFactory();Treetree1newTree(10,20,factory.getTreeType(Oak,Green,Smooth));Treetree2newTree(15,25,factory.getTreeType(Pine,Dark Green,Rough));Treetree3newTree(10,20,factory.getTreeType(Oak,Green,Smooth));tree1.display();tree2.display();tree3.display();}}七.代碼解析TreeType / ConcreteTreeType享元角色TreeType抽象享元定義接口內(nèi)部狀態(tài)name、color、texture保存在具體享元對(duì)象中一旦創(chuàng)建不會(huì)修改。Display(x,y)不保存坐標(biāo)坐標(biāo)作為外部狀態(tài)參數(shù)傳入這是享元關(guān)鍵享元對(duì)象不能存儲(chǔ)外部可變數(shù)據(jù)。TreeFactory享元工廠使用哈希unordered_map作為對(duì)象池根據(jù)內(nèi)部狀態(tài)拼接keykey存在直接返回舊對(duì)象不存在就新建放入池所有共享對(duì)象統(tǒng)一由工廠獲取客戶端不能直接new具體享元。Tree客戶端輔助Tree保存獨(dú)有的外部狀態(tài)x、y持有共享的享元對(duì)象指針業(yè)務(wù)調(diào)用時(shí)把自己的外部狀態(tài)傳給享元對(duì)象。運(yùn)行現(xiàn)象相同key只會(huì)打印一次Created new TreeType代表對(duì)象只實(shí)例化一次多處復(fù)用。八.總結(jié)享元模式核心區(qū)分內(nèi)部狀態(tài)不變放享元對(duì)象共享和外部狀態(tài)變化客戶端維護(hù)傳入工廠做對(duì)象池緩存復(fù)用細(xì)粒度對(duì)象節(jié)約內(nèi)存。應(yīng)用場(chǎng)景游戲大量重復(fù)圖形元素樹木、怪物模板位置是外部狀態(tài)文本編輯器字符對(duì)象字體樣式內(nèi)部狀態(tài)字符位置外部狀態(tài)連接池?cái)?shù)據(jù)庫(kù)連接池、對(duì)象池復(fù)用昂貴對(duì)象。關(guān)鍵點(diǎn)歸屬結(jié)構(gòu)型設(shè)計(jì)模式別名輕量級(jí)模式。五大角色抽象享元Flyweight、具體享元ConcreteFlyweight、非共享享元UnsharedConcreteFlyweight、享元工廠FlyweightFactory、客戶端Client。核心內(nèi)部狀態(tài)可共享外部狀態(tài)客戶端傳入享元對(duì)象不存外部狀態(tài)。適合系統(tǒng)存在大量細(xì)粒度相似對(duì)象不適合對(duì)象數(shù)量少狀態(tài)復(fù)雜多變。對(duì)比區(qū)分享元模式是對(duì)象池/緩存復(fù)用對(duì)象省內(nèi)存單例是全局只允許一個(gè)實(shí)例兩者意圖不一樣。