1. 程式人生 > >設計模式-享元模式(Flyweight)

設計模式-享元模式(Flyweight)

概述

  • 定義 : 提供了減少物件數量從而改善應用所需的物件結構的方式
  • 運用共享技術有效的支援大量細粒度的物件
  • 型別 : 結構型

適用場景

  • 常常應用於系統底層的開發, 以便解決系統的效能問題
  • 系統有大量相似的物件, 需要緩衝池的場景

優點

  • 減少物件的建立, 降低記憶體中物件的數量, 降低系統的記憶體, 提高效率
  • 減少記憶體之外的其他資源佔用

缺點

  • 關注內/外部狀態, 關注執行緒安全問題
  • 使系統, 程式的邏輯複雜化

擴充套件

  • 內部狀態
  • 外部狀態

模式角色

  • Flyweight : 描述一個介面,通過這個介面f l y w e i g h t可以接受並作用於外部狀態

  • ConcreteFlyweight : 實 現 F l y w e i g h t 接 口 , 並 為 內 部 狀 態 ( 如 果 有 的 話 ) 增 加 存 儲 空 間 。
    ConcreteFlyweight物件必須是可共享的。它所儲存的狀態必須是內部的;即,它必
    須獨立於 ConcreteFlyweight物件的場景。

  • UNsharedConcreteFlyweight : 並非所有的F l y w e i g h t子類都需要被共享。 F l y w e i g h t介面使共享成為可能,但它並不強制共享。在F l y w e i g h t物件結構的某些層次, U n s h a r e d C o n c r e t e F l y w e i g h t物件通常將C o n c r e t e F l y w e i g h t物件作為子節點

  • FlyweightFactory

    • 建立並管理Flyweight 物件。
    • 確保合理地共享Flyweight當用戶請求一個Flyweight 時,F l y w e i g h t F a c t o r y物件提供一個已建立的例項或者建立一個(如果不存在的話)。
  • Client

    • 維持一個對Flyweight 的引用。
    • 計算或儲存一個(多個)Flyweight 的外部狀態。

程式碼實現

場景:

1.有一個員工介面Employee, 對應Flyweight介面
2.部門經理類Manger實現了員工介面, 對應ConcreteFlyweight介面實現
3. 一個EmployeeFactory類用於管理Employee, 對應FlyweightFactory
4. 場景就是部門經理做年終報告
程式碼如下 :

/**
 * Flyweight角色
 *
 * @author 七夜雪
 * @create 2018-11-23 18:52
 */
public interface Employee {
    void report();
}
/**
 * ConcreteFlyweight 角色
 * @author 七夜雪
 */
public class Manager implements Employee {
    @Override
    public void report() {
        System.out.println(reportContent);
    }
    // 這個就是內部狀態
    private String title = "部門經理";
    private String department;
    private String reportContent;

    public void setReportContent(String reportContent) {
        this.reportContent = reportContent;
    }

    public Manager(String department) {
        this.department = department;
    }
}
/**
 * FlyweightFactory角色
 *
 * @author 七夜雪
 * @create 2018-11-23 14:07
 */
public class EmployeeFactory {
    private static final Map<String,Employee> EMPLOYEE_MAP = new HashMap<String,Employee>();

    public static Employee getManager(String department){
        Manager manager = (Manager) EMPLOYEE_MAP.get(department);

        if(manager == null){
            manager = new Manager(department);
            System.out.print("建立部門經理:"+department);
            String reportContent = department+"部門彙報:此次報告的主要內容是......";
            manager.setReportContent(reportContent);
            System.out.println(" 建立報告:"+reportContent);
            EMPLOYEE_MAP.put(department,manager);

        }
        return manager;
    }

}

測試程式碼:

    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();

        }

    }

測試結果:

建立部門經理:測試 建立報告:測試部門彙報:此次報告的主要內容是…
測試部門彙報:此次報告的主要內容是…
建立部門經理:開發 建立報告:開發部門彙報:此次報告的主要內容是…
開發部門彙報:此次報告的主要內容是…
建立部門經理:人力 建立報告:人力部門彙報:此次報告的主要內容是…
人力部門彙報:此次報告的主要內容是…
建立部門經理:產品 建立報告:產品部門彙報:此次報告的主要內容是…
產品部門彙報:此次報告的主要內容是…
人力部門彙報:此次報告的主要內容是…
產品部門彙報:此次報告的主要內容是…
開發部門彙報:此次報告的主要內容是…
人力部門彙報:此次報告的主要內容是…
開發部門彙報:此次報告的主要內容是…
人力部門彙報:此次報告的主要內容是…

從測試結果來看, 只有第一次使用時才建立了Manager物件, 其餘都是直接從Map中獲取了, 這就是享元模式的概念