一. 定義與類型
定義:提供了減少對象數量從而改善應用所需的對象結構的方式,運用共享技術有效地支持大量細粒度的對象
類型:結構性
二. 使用場景
(1) 常常應用於系統底層的開發,以便解決系統的性能問題
(2) 系統有大量相似對象,需要緩沖池的場景
三. 優缺點
優點:
(1) 減少對象的創建,降低內存中對象的數量,降低系統的內存,提高效率
(2) 減少內存之外的其他資源占用
缺點:
(1) 關注內/外狀態,關注線程安全問題
(2) 使系統,程序的邏輯復雜化
四.享元——擴展
內部狀態
外部狀態
五. 相關設計模式
享元模式和代理模式
代理模式就是代理一個類,如果生成這個代理類需要花費的資源和時間比較多,就可以使用享元模式,提高系統的速度
享元模式和單例模式
單例模式中的容器單例就是享元模式的一種使用
六. Coding
以一個業務場景為例,假設每年年底的時候公司中的部門經理都需要寫年終報告,但是可能不止要報告一次,需要重復報告。
使用享元模式,可以很好的完成上面的例子。
先創建一個接口:
/** * @program: designModel * @description: * @author: YuKai Fan * @create: 2019-02-12 10:01 **/ public interface Emplyee { void report(); }
再創建一個經理實體類,來實現接口
/** * @program: designModel * @description: 部門manager * @author: YuKai Fan * @create: 2019-02-12 10:01 **/ public class Manager implements Emplyee { public void report() { System.out.println(reportContent); } private String title = "部門經理"; private String department;//部門 private String reportContent;//報告內容 public Manager(String department) { this.department = department; } public void setReportContent(String reportContent) { this.reportContent = reportContent; } }
在創建一個員工工廠,通過工廠在獲取manager,因為只需要manager做報告,不需要employee。
/** * @program: designModel * @description: 員工工廠 * @author: YuKai Fan * @create: 2019-02-12 10:04 **/ public class EmployeeFactory {
//因為在享元模式中,一般要考慮線程安全問題,但是還是要看業務場景來使用 private static final Map<String, Emplyee> EMPLYEE_MAP = new HashMap<String, Emplyee>(); public static Emplyee getManager(String department) { Manager manager = (Manager) EMPLYEE_MAP.get(department); if (manager == null) { manager = new Manager(department); System.out.print("創建部門經理:" + department); String reportContent = department + "部門匯報:此次報告的主要內容是。。。。"; manager.setReportContent(reportContent); System.out.println(" 創建報告:" + reportContent); EMPLYEE_MAP.put(department, manager); } return manager; } }
應用層:
/** * @program: designModel * @description: * @author: YuKai Fan * @create: 2019-02-12 10:08 **/ 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(); } } }
結果:
UML類圖:
從結果可以看出,當部門經理做報告時只需要創建一次即可,下次不需要再次創建。減少了對象的創建
在上面的代碼例子中,department相當於外部狀態。因為它依賴於外部的傳入,為了方便理解,創建一個title屬性,它就是一個內部狀態,它不隨外部狀態department的變化而變化。
七. 源碼分析
(1)
Integer類就是典型的享元模式的例子
Integer.valueOf中有一個IntegerCache,上面的代碼中就對傳入的值進行判斷。如果是從IntegerCache中取出就直接返回,否則就new一個Integer對象。這也就是如果傳入的int值不在固定的范圍類,它們做==的時候一定是false,因為不是同一個對象。其中low=-128,high=127.
還有Long類的valueOf,也是同上的道理。
(2)
tomcat中的GenericObjectPoolConfig連接池