設計模式---享元模式
簡述
- 類型:結構型
- 目的:降低對象創建時大量屬性也隨之被新建而帶來的性能上的消耗
話不多説,我們看一個案例。
優化案例
最初版v0
現在需要採購一批辦公用的電腦,以下是 Computer
類的定義。
class Computer { private String sn; // 序列號,電腦的唯一識別碼 private String brand; // 品牌 private String title; // 一個系列的名稱,如Lenovo的Thinkpad private String cpu; private String memory; private String disk; private String gpu; private String keyboard; private String display; public Computer(String sn, String brand, String title, String cpu, String memory, String disk, String gpu, String keyboard, String display) { this.sn = sn; this.brand = brand; this.title = title; this.cpu = cpu; this.memory = memory; this.disk = disk; this.gpu = gpu; this.keyboard = keyboard; this.display = display; } }
現在公司要採購兩種電腦總計1000台,以下是模擬採購的代碼。
class Client { public static void main(String[] args) { List<Computer> purchase = new ArrayList<>(); for (int i = 0; i < n; i ++) { purchase.add(new Computer(UUID.randomUUID().toString(), "華為", "MateBook16", "鋭龍7 5800H標壓", "16GB DDR4 雙通道", "512GB NVMe PCle SSD", "gpu", "全尺寸背光鍵盤", "16英寸"); } } }
循環中每一次都要生成一個新的Computer對象,並且該對象中有很多String類型的屬性,因為String是一個引用數據類型,所以會隨之生成很多的引用,從而降低系統的性能。實際上,採購的計算機只要型號相同,配置參數也就隨之相同且不會再改變,唯一會改變的其實就只有機器的序列號而已,所以我們沒有每追加一台電腦就重新設置一遍所有參數的必要。而且如果中途需要對於採購訂單的機器參數進行修改,那就必須迭代清單中的所有對象,對每個對象進行修改,又是一件效率低下的事。
為了解決這個問題,我們引入了享元模式。下面是修改後的代碼。
修改版v1
class Computer { private String sn; // 序列號,電腦的唯一識別碼 private ComputerSpec spec; // 依賴規格的具體屬性 → 依賴ComputerSpec類,迪米特法則 public Computer(String sn, ComputerSpec spec) { this.sn = sn; this.spec = spec; this.title = title; this.model = model; this.cpu = cpu; this.memory = memory; this.disk = disk; this.gpu = gpu; this.keyboard = keyboard; this.display = display; } } enum ComputerSpec { // 定義一個計算機規格類 MATEBOOK16("華為", "MateBook16", "鋭龍7 5800H標壓", "16GB DDR4 雙通道", "512GB NVMe PCle SSD", "gpu", "全尺寸背光鍵盤", "16英寸"); public String brand; // 品牌 public String title; // 一個系列的名稱,如Lenovo的Thinkpad public String cpu; public String memory; public String disk; public String gpu; public String keyboard; public String display; ComputerSpec(String sn, String brand, String title, String cpu, String memory, String disk, String gpu, String keyboard, String display) { this.brand = brand; this.title = title; this.model = model; this.cpu = cpu; this.memory = memory; this.disk = disk; this.gpu = gpu; this.keyboard = keyboard; this.display = display; } }
來看看修改後的採購如何模擬實現。
class Client { public static void main(String[] args) { List<Computer> purchase = new ArrayList<>(); for (int i = 0; i < n; i ++) { purchase.add(new Computer(UUID.randomUUID().toString(), ComputerSpec.MATEBOOK16)); } // 由於訂單錯誤,現在需要批量將MateBook16修改為MateBook16s ComputerSpec.MATEBOOK16.title = "MateBook16s"; } }
使用享元模式,將 Computer
對象創建時不變的屬性封裝到 ComputerSpec
中, 內部狀態
與 外部狀態
分開,內部狀態直接引用相同的數據源,而不是每次都重新生成新的數據,從而大幅提升系統性能。並且,需要對於數據統一修改時,由於數據源引用相同,只需要修改內部狀態的對應屬性即可修改所有數據。
ComputerSpec sn
總結
優點
- 由於多個對象的屬性引用相同,從而極大程度的降低了系統性能的消耗。
- 由於多個屬性被封裝成新的類,對象與屬性間的依賴減少,從而降低了對象創建的複雜度。
缺點
- 增加了開發人員對於系統業務理解的難度。
適用場景
- 當對象的絕大多數屬性與對象本身不是一對一而是一對多的關係時。 換言之,多個對象公用一套屬性時 。
「其他文章」
- 記一次批量更新整型類型的列 → 探究 UPDATE 的使用細節
- 編碼中的Adapter,不僅是一種設計模式,更是一種架構理念與解決方案
- 線程池底層原理詳解與源碼分析
- 30分鐘掌握 Webpack
- 線性迴歸大結局(嶺(Ridge)、 Lasso迴歸原理、公式推導),你想要的這裏都有
- Django 之路由層
- 【前端必會】webpack loader 到底是什麼
- day42-反射01
- 中心化決議管理——雲端分析
- HashMap底層原理及jdk1.8源碼解讀
- 詳解JS中 call 方法的實現
- 打印 Logger 日誌時,需不需要再封裝一下工具類?
- 初識設計模式 - 代理模式
- 設計模式---享元模式
- 密碼學奇妙之旅、01 CFB密文反饋模式、AES標準、Golang代碼
- [ML從入門到入門] 支持向量機:從SVM的推導過程到SMO的收斂性討論
- 從應用訪問Pod元數據-DownwardApi的應用
- Springboot之 Mybatis 多數據源實現
- Java 泛型程序設計
- CAS核心思想、底層實現