摘要:類圖相關(guān)的設(shè)計(jì)模式享元模式和代理模式當(dāng)代理模式消耗性能比較大的時(shí)候,就可以用享元模式享元模式和單例模式容器單例,享元模式就是復(fù)用對象的思想。源碼中的享元模式源碼地址享元模式參考慕課網(wǎng)設(shè)計(jì)模式精講設(shè)計(jì)模式讀書筆記享元模式
0x01.定義與類型
定義:提供了減少對象數(shù)量從而改善應(yīng)用所需的對象結(jié)構(gòu)的方法,系統(tǒng)使用少量對象,而且這些都比較相似,狀態(tài)變化小,可以實(shí)現(xiàn)對象的多次復(fù)用。
運(yùn)用共享技術(shù)有效地支持大量細(xì)粒度的對象
類型:結(jié)構(gòu)型
享元模式的兩個(gè)狀態(tài):
內(nèi)部狀態(tài):在享元對象內(nèi)部不隨外界環(huán)境改變而改變的共享部分。
外部狀態(tài):隨著環(huán)境的改變而改變,不能夠共享的狀態(tài)就是外部狀態(tài)。
由于享元模式區(qū)分了內(nèi)部狀態(tài)和外部狀態(tài),所以我們可以通過設(shè)置不同的外部狀態(tài)使得相同的對象可以具備一些不同的特性,而內(nèi)部狀態(tài)設(shè)置為相同部分。在我們的程序設(shè)計(jì)過程中,我們可能會需要大量的細(xì)粒度對象來表示對象,如果這些對象除了幾個(gè)參數(shù)不同外其他部分都相同,這個(gè)時(shí)候我們就可以利用享元模式來大大減少應(yīng)用程序當(dāng)中的對象。如何利用享元模式呢?這里我們只需要將他們少部分的不同的部分當(dāng)做參數(shù)移動到類實(shí)例的外部去,然后再方法調(diào)用的時(shí)候?qū)⑺麄儌鬟f過來就可以了。這里也就說明了一點(diǎn):內(nèi)部狀態(tài)存儲于享元對象內(nèi)部,而外部狀態(tài)則應(yīng)該由客戶端來考慮。
UML類圖
Java實(shí)現(xiàn)
/** * 享元對象接口 */ public interface Flyweight { void operation(String extrinsicState); } /** * 享元對象工廠類,享元類 */ public final class FlyweightFactory { /** * 享元類容器 */ private static Mapflyweights = new HashMap<>(); public static Flyweight getFlyweight (String key) { if (flyweights.containsKey(key)) { return flyweights.get(key); } else { Flyweight flyweight = new ConcreteFlyweight(key); flyweights.put(key, flyweight); return flyweight; } } public static int size () { return flyweights.size(); } } /** * 可以被共享的對象 */ public class ConcreteFlyweight implements Flyweight{ private String intrinsicState; public ConcreteFlyweight(String intrinsicState) { this.intrinsicState = intrinsicState; } @Override public void operation(String extrinsicState) { System.out.println(this.intrinsicState); System.out.println(extrinsicState); } } /** * 不被共享的對象 */ public class UnsharedConcreteFlyweight implements Flyweight { private String allState; public UnsharedConcreteFlyweight(String allState) { this.allState = allState; } @Override public void operation(String extrinsicState) { System.out.println(this.allState); System.out.println(extrinsicState); } }
測試與應(yīng)用類
/** * 應(yīng)用與測試 */ public class Test { public static void main(String[] args) { Stream.of("1", "1", "2", "2", "3").forEach(key -> { Flyweight flyweight = FlyweightFactory.getFlyweight(key); flyweight.operation("測試" + key); }); System.out.println("size: " + FlyweightFactory.size()); } }
輸出結(jié)果
1---:測試1 1---:測試1 2---:測試2 2---:測試2 3---:測試3 size: 3
享元模式角色介紹
Flyweight: 抽象享元類。所有具體享元類的超類或者接口,通過這個(gè)接口,F(xiàn)lyweight可以接受并作用于外部專題。
ConcreteFlyweight: 具體享元類。指定內(nèi)部狀態(tài),為內(nèi)部狀態(tài)增加存儲空間。
UnsharedConcreteFlyweight: 非共享具體享元類。指出那些不需要共享的Flyweight子類。
FlyweightFactory: 享元工廠類。用來創(chuàng)建并管理Flyweight對象,它主要用來確保合理地共享Flyweight,當(dāng)用戶請求一個(gè)Flyweight時(shí),F(xiàn)lyweightFactory就會提供一個(gè)已經(jīng)創(chuàng)建的Flyweight對象或者新建一個(gè)(如果不存在)。
享元模式的核心在于享元工廠類,享元工廠類的作用在于提供一個(gè)用于存儲享元對象的享元池,用戶需要對象時(shí),首先從享元池中獲取,如果享元池中不存在,則創(chuàng)建一個(gè)新的享元對象返回給用戶,并在享元池中保存該新增對象。
0x02.適用場景如果一個(gè)系統(tǒng)中存在大量的相同或者相似的對象,由于這類對象的大量使用,會造成系統(tǒng)內(nèi)存的耗費(fèi),可以使用享元模式緩沖池來減少系統(tǒng)中對象的數(shù)量。
對象的大部分狀態(tài)都可以外部化,可以將這些外部狀態(tài)傳入對象中。
常常應(yīng)用于系統(tǒng)底層的開發(fā),以便解決系統(tǒng)的性能問題。
0x03.優(yōu)點(diǎn)減少對象的創(chuàng)建,降低內(nèi)存中對象的數(shù)量,降低系統(tǒng)的內(nèi)存,提高效率。
減少內(nèi)存之外的其他資源占用。
0x04.缺點(diǎn)由于享元模式需要區(qū)分外部狀態(tài)和內(nèi)部狀態(tài),使得應(yīng)用程序在某種程度上來說更加復(fù)雜化了。
為了使對象可以共享,享元模式需要將享元對象的狀態(tài)外部化,而讀取外部狀態(tài)使得運(yùn)行時(shí)間變長。
需要關(guān)注內(nèi)/外部狀態(tài),關(guān)注線程安全問題。
0x05.模式樣例假設(shè)一個(gè)公司中的每個(gè)部門的部門經(jīng)理都要進(jìn)行匯報(bào)不止一次
Java實(shí)現(xiàn)
/** * 員工接口 */ public interface Employee { void report(); } /** * 員工工廠 */ public class EmployeeFactory { private static final MapEMPLOYEE_MAP = new HashMap<>(); public static Employee getManager(String department) { Manager manager = (Manager) EMPLOYEE_MAP.get(department); if (manager == null) { manager = new Manager(department); System.out.println("創(chuàng)建部門經(jīng)理:" + department); String reportContent = department + "部門匯報(bào):此次報(bào)告內(nèi)容是。。。"; manager.setReportContent(reportContent); System.out.println("創(chuàng)建報(bào)告: " + reportContent); EMPLOYEE_MAP.put(department, manager); } return manager; } } /** * 部門經(jīng)理 */ public class Manager implements Employee { /** * 內(nèi)部狀態(tài) */ private String title = "部門經(jīng)理"; /** * 外部狀態(tài),需要在應(yīng)用層引入,就是外部狀態(tài) */ private String department; private String reportContent; public Manager(String department) { this.department = department; } public void setReportContent(String reportContent) { this.reportContent = reportContent; } @Override public void report() { System.out.println(reportContent); } }
測試與應(yīng)用
/** * 測試與應(yīng)用 */ public class Test { private static final String[] departments = {"RD", "QA", "PM", "BD"}; /** * 要注意線程安全的問題 */ public static void main(String[] args) { for (int i = 0; i < 10; i ++) { String department = departments[(int) (Math.random() * departments.length)]; Manager manager = (Manager) EmployeeFactory.getManager(department); manager.report(); } System.out.println(EmployeeFactory.size()); } }
輸出結(jié)果
創(chuàng)建部門經(jīng)理:BD 創(chuàng)建報(bào)告: BD部門匯報(bào):此次報(bào)告內(nèi)容是。。。 BD部門匯報(bào):此次報(bào)告內(nèi)容是。。。 創(chuàng)建部門經(jīng)理:PM 創(chuàng)建報(bào)告: PM部門匯報(bào):此次報(bào)告內(nèi)容是。。。 PM部門匯報(bào):此次報(bào)告內(nèi)容是。。。 創(chuàng)建部門經(jīng)理:QA 創(chuàng)建報(bào)告: QA部門匯報(bào):此次報(bào)告內(nèi)容是。。。 QA部門匯報(bào):此次報(bào)告內(nèi)容是。。。 QA部門匯報(bào):此次報(bào)告內(nèi)容是。。。 QA部門匯報(bào):此次報(bào)告內(nèi)容是。。。 BD部門匯報(bào):此次報(bào)告內(nèi)容是。。。 PM部門匯報(bào):此次報(bào)告內(nèi)容是。。。 創(chuàng)建部門經(jīng)理:RD 創(chuàng)建報(bào)告: RD部門匯報(bào):此次報(bào)告內(nèi)容是。。。 RD部門匯報(bào):此次報(bào)告內(nèi)容是。。。 PM部門匯報(bào):此次報(bào)告內(nèi)容是。。。 PM部門匯報(bào):此次報(bào)告內(nèi)容是。。。 4
UML類圖
0x06.相關(guān)的設(shè)計(jì)模式享元模式和代理模式:當(dāng)代理模式消耗性能比較大的時(shí)候,就可以用享元模式
享元模式和單例模式:容器單例,享元模式就是復(fù)用對象的思想。
0x07.源碼中的享元模式JDK: Integer.valueOf(), --IntegerCache
Tomcat: GenericObjectPoolConfig, GenericKeyedPoolConfig
0x08.源碼地址享元模式: https://github.com/sigmako/design-pattern/tree/master/fiyweight
0x09.參考慕課網(wǎng)設(shè)計(jì)模式精講: https://coding.imooc.com/class/270.html
設(shè)計(jì)模式讀書筆記----享元模式: https://www.cnblogs.com/chenssy/p/3330555.html
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/75811.html
摘要:而享元模式的核心就是運(yùn)用共享技術(shù)來有效支持大量細(xì)粒度的對象。享元模式要求將對象的屬性劃分為內(nèi)部狀態(tài)和外部狀態(tài),所以在了解享元模式之前我們先要了解兩個(gè)概念內(nèi)部狀態(tài)外部狀態(tài)。一般情況下在這四種情況下應(yīng)該考慮使用享元模式。 享元模式(flyweight)是一種用于性能優(yōu)化的模式,之所以用fly其意為蠅量級。而享元模式的核心就是運(yùn)用共享技術(shù)來有效支持大量細(xì)粒度的對象。雖然面向?qū)ο罂梢苑浅7奖愕?..
摘要:作者按每天一個(gè)設(shè)計(jì)模式旨在初步領(lǐng)會設(shè)計(jì)模式的精髓,目前采用和兩種語言實(shí)現(xiàn)。享元模式提醒我們將一個(gè)對象的屬性劃分為內(nèi)部和外部狀態(tài)。 作者按:《每天一個(gè)設(shè)計(jì)模式》旨在初步領(lǐng)會設(shè)計(jì)模式的精髓,目前采用javascript和python兩種語言實(shí)現(xiàn)。誠然,每種設(shè)計(jì)模式都有多種實(shí)現(xiàn)方式,但此小冊只記錄最直截了當(dāng)?shù)膶?shí)現(xiàn)方式 :) 個(gè)人技術(shù)博客-godbmw.com 歡迎來玩! 每周至少 1 篇原創(chuàng)...
摘要:作者按每天一個(gè)設(shè)計(jì)模式旨在初步領(lǐng)會設(shè)計(jì)模式的精髓,目前采用和兩種語言實(shí)現(xiàn)。享元模式提醒我們將一個(gè)對象的屬性劃分為內(nèi)部和外部狀態(tài)。 作者按:《每天一個(gè)設(shè)計(jì)模式》旨在初步領(lǐng)會設(shè)計(jì)模式的精髓,目前采用javascript和python兩種語言實(shí)現(xiàn)。誠然,每種設(shè)計(jì)模式都有多種實(shí)現(xiàn)方式,但此小冊只記錄最直截了當(dāng)?shù)膶?shí)現(xiàn)方式 :) 個(gè)人技術(shù)博客-godbmw.com 歡迎來玩! 每周至少 1 篇原創(chuàng)...
摘要:享元模式享元模式是一種優(yōu)化程序性能的模式本質(zhì)為減少對象創(chuàng)建的個(gè)數(shù)。 享元模式 享元模式是一種優(yōu)化程序性能的模式, 本質(zhì)為減少對象創(chuàng)建的個(gè)數(shù)。 以下情況可以使用享元模式:有大量相似的對象, 占用了大量內(nèi)存對象中大部分狀態(tài)可以抽離為外部狀態(tài) demo某商家有 50 種男款內(nèi)衣和 50 種款女款內(nèi)衣, 要展示它們 方案一: 造 50 個(gè)塑料男模和 50 個(gè)塑料女模, 讓他們穿上展示, 代碼如...
摘要:享元模式通過分析應(yīng)用程序的對象,將其解析為內(nèi)在數(shù)據(jù)和外在數(shù)據(jù),減少對象數(shù)量,從而提高程序的性能。通過這種方式進(jìn)行事件綁定,可以減少事件處理程序的數(shù)量,這種方式叫做事件委托,也是運(yùn)用了享元模式的原理。事件處理程序是公用的內(nèi)在部分,每個(gè)菜單項(xiàng)各 github 全文地址 : YOU-SHOULD-KNOW-JS JavaScript設(shè)計(jì)模式之外觀模式 概念 外觀模式:為一組復(fù)雜子系統(tǒng)接口提...
閱讀 1278·2021-10-14 09:50
閱讀 1579·2019-08-30 15:54
閱讀 1040·2019-08-30 11:22
閱讀 2931·2019-08-30 10:50
閱讀 1816·2019-08-29 18:39
閱讀 3065·2019-08-29 13:07
閱讀 2087·2019-08-28 17:54
閱讀 761·2019-08-26 17:44