Java设计模式之享元模式(UML类图分析+代码详解)
大家好,我是一名在算法之路上不斷前進的小小程序猿!體會算法之美,領悟算法的智慧~
希望各位博友走過路過可以給我點個免費的贊,你們的支持是我不斷前進的動力!!
加油吧!未來可期!!
本文將介紹java設計模式之享元模式
案例引入:
展示網(wǎng)站項目需求:小型的外包項目,給客戶A做一個產(chǎn)品展示網(wǎng)站,客戶A的朋友感覺效果不錯,也希 望做這樣的產(chǎn)品展示網(wǎng)站,但是要求都有些不同:
1) 有客戶要求以新聞的形式發(fā)布
2) 有客戶人要求以博客的形式發(fā)布
3) 有客戶希望以微信公眾號的形式發(fā)布
傳統(tǒng)方案解決網(wǎng)站展現(xiàn)項目
1) 直接復制粘貼一份,然后根據(jù)客戶不同要求,進行定制修改
2) 給每個網(wǎng)站租用一個空間
3) 方案設計示意圖
傳統(tǒng)方案解決網(wǎng)站展現(xiàn)項目-問題分析
1) 需要的網(wǎng)站結構相似度很高,而且都不是高訪問量網(wǎng)站,如果分成多個虛擬空間來 處理,相當于一個相同網(wǎng)站的實例對象很多,造成服務器的資源浪費
2) 解決思路:整合到一個網(wǎng)站中,共享其相關的代碼和數(shù)據(jù),對于硬盤、內(nèi)存、CPU、 數(shù)據(jù)庫空間等服務器資源都可以達成共享,減少服務器資源
3) 對于代碼來說,由于是一份實例,維護和擴展都更加容易
4) 上面的解決思路就可以使用 享元模式 來解決?
享元模式基本介紹
1) 享元模式(Flyweight Pattern) 也叫 蠅量模式: 運 用共享技術有效地支持大量細粒度的對象
2) 常用于系統(tǒng)底層開發(fā),解決系統(tǒng)的性能問題。像數(shù)據(jù)庫連接池,里面都是創(chuàng)建好的連接對象,在這些連接對象中有我們需要的則直接拿來用,避 免重新創(chuàng)建,如果沒有我們需要的,則創(chuàng)建一個
3) 享元模式能夠解決重復對象的內(nèi)存浪費的問題, 當系統(tǒng)中有大量相似對象,需要緩沖池時。不需 總是創(chuàng)建新對象,可以從緩沖池里拿。這樣可以 降低系統(tǒng)內(nèi)存,同時提高效率
4) 享元模式經(jīng)典的應用場景就是池技術了,String常 量池、數(shù)據(jù)庫連接池、緩沖池等等都是享元模式 的應用,享元模式是池技術的重要實現(xiàn)方式
享元模式的原理類圖
?內(nèi)部狀態(tài)和外部狀態(tài)
比如圍棋、五子棋、跳棋,它們都有大量的棋子對象,圍棋和五子棋只有黑白兩色,跳棋顏色多一 點,所以棋子顏色就是棋子的內(nèi)部狀態(tài);而各個棋子之間的差別就是位置的不同,當我們落子后, 落子顏色是定的,但位置是變化的,所以棋子坐標就是棋子的外部狀態(tài)
1) 享元模式提出了兩個要求:細粒度和共享對象。這里就涉及到內(nèi)部狀態(tài)和外部狀態(tài) 了,即將對象的信息分為兩個部分:內(nèi)部狀態(tài)和外部狀態(tài)
2) 內(nèi)部狀態(tài)指對象共享出來的信息,存儲在享元對象內(nèi)部且不會隨環(huán)境的改變而改變
3) 外部狀態(tài)指對象得以依賴的一個標記,是隨環(huán)境改變而改變的、不可共享的狀態(tài)。
4) 舉個例子:圍棋理論上有361個空位可以放棋子,每盤棋都有可能有兩三百個棋子對 象產(chǎn)生,因為內(nèi)存空間有限,一臺服務器很難支持更多的玩家玩圍棋游戲,如果用 享元模式來處理棋子,那么棋子對象就可以減少到只有兩個實例,這樣就很好的解 決了對象的開銷問題。
享元模式解決網(wǎng)站展現(xiàn)項目
享元模式應用實例 1) 應用實例要求 使用享元模式完成,前面提出的網(wǎng)站外包問題 2) 思路分析和圖解(類圖) 3) 代碼實現(xiàn)
package flyweight;/* <---這是包名 -*- coding:utf-8 -*- 作者:bob-coding 日期:2022年10月15日12:11 敲碼百遍,其意多見!!沖沖沖!!!*/import java.util.HashMap;public class FlyWeight {public static void main(String[] args) { // TODO Auto-generated method stub// 創(chuàng)建一個工廠類WebSiteFactory factory = new WebSiteFactory();// 客戶要一個以新聞形式發(fā)布的網(wǎng)站W(wǎng)ebSite webSite1 = factory.getWebSiteCategory("新聞");webSite1.use(new User("tom"));// 客戶要一個以博客形式發(fā)布的網(wǎng)站W(wǎng)ebSite webSite2 = factory.getWebSiteCategory("博客");webSite2.use(new User("jack"));// 客戶要一個以博客形式發(fā)布的網(wǎng)站W(wǎng)ebSite webSite3 = factory.getWebSiteCategory("博客");webSite3.use(new User("smith"));// 客戶要一個以博客形式發(fā)布的網(wǎng)站W(wǎng)ebSite webSite4 = factory.getWebSiteCategory("博客");webSite4.use(new User("king"));System.out.println("網(wǎng)站的分類共" + factory.getWebSiteCount()+"個");} }//具體網(wǎng)站 class ConcreteWebSite extends WebSite {//共享的部分,內(nèi)部狀態(tài)private String type = ""; //網(wǎng)站發(fā)布的形式(類型)//構造器public ConcreteWebSite(String type) {this.type = type;}@Overridepublic void use(User user) {// TODO Auto-generated method stubSystem.out.println("網(wǎng)站的發(fā)布形式為:" + type + " 在使用中 .. 使用者是" + user.getName());}}// 網(wǎng)站工廠類,根據(jù)需要返回一個網(wǎng)站 class WebSiteFactory {//集合, 充當池的作用private HashMap<String, ConcreteWebSite> pool = new HashMap<>();//根據(jù)網(wǎng)站的類型,返回一個網(wǎng)站, 如果沒有就創(chuàng)建一個網(wǎng)站,并放入到池中,并返回public WebSite getWebSiteCategory(String type) {if(!pool.containsKey(type)) {//就創(chuàng)建一個網(wǎng)站,并放入到池中pool.put(type, new ConcreteWebSite(type));}return (WebSite)pool.get(type);}//獲取網(wǎng)站分類的總數(shù) (池中有多少個網(wǎng)站類型)public int getWebSiteCount() {return pool.size();} }class User {private String name;public User(String name) {super();this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}}abstract class WebSite {public abstract void use(User user);//抽象方法 }?
?享元模式在JDK-Interger的應用源碼分析
1) Integer中的享元模式 2) 代碼分析+Debug源碼+說明
public class FlyWeight {public static void main(String[] args) {// TODO Auto-generated method stub//如果 Integer.valueOf(x) x 在 -128 --- 127 直接,就是使用享元模式返回,如果不在//范圍類,則仍然 new //小結://1. 在valueOf 方法中,先判斷值是否在 IntegerCache 中,如果不在,就創(chuàng)建新的Integer(new), 否則,就直接從 緩存池返回//2. valueOf 方法,就使用到享元模式//3. 如果使用valueOf 方法得到一個Integer 實例,范圍在 -128 - 127 ,執(zhí)行速度比 new 快Integer x = Integer.valueOf(127); // 得到 x實例,類型 IntegerInteger y = new Integer(127); // 得到 y 實例,類型 IntegerInteger z = Integer.valueOf(127);//..Integer w = new Integer(127);System.out.println(x.equals(y)); // 大小,trueSystem.out.println(x == y ); // falseSystem.out.println(x == z ); // trueSystem.out.println(w == x ); // falseSystem.out.println(w == y ); // falseInteger x1 = Integer.valueOf(200);Integer x2 = Integer.valueOf(200);System.out.println("x1==x2" + (x1 == x2)); // false}}分析:如果 Integer.valueOf(x) x 在 ?-128 --- 127 直接,就是使用享元模式返回,如果不在范圍內(nèi),則仍然 new?
小結:
1. 在valueOf 方法中,先判斷值是否在 IntegerCache 中,如果不在,就創(chuàng)建新的Integer(new), 否則,就直接從 緩存池返回
2. valueOf 方法,就使用到享元模式
3. 如果使用valueOf 方法得到一個Integer 實例,范圍在 -128 - 127 ,執(zhí)行速度比 new 快
享元模式的注意事項和細節(jié)
1) 在享元模式這樣理解,“享”就表示共享,“元”表示對象
2) 系統(tǒng)中有大量對象,這些對象消耗大量內(nèi)存,并且對象的狀態(tài)大部分可以外部化時, 我們就可以考慮選用享元模式
3) 用唯一標識碼判斷,如果在內(nèi)存中有,則返回這個唯一標識碼所標識的對象,用 HashMap/HashTable存儲
4) 享元模式大大減少了對象的創(chuàng)建,降低了程序內(nèi)存的占用,提高效率
5) 享元模式提高了系統(tǒng)的復雜度。需要分離出內(nèi)部狀態(tài)和外部狀態(tài),而外部狀態(tài)具有 固化特性,不應該隨著內(nèi)部狀態(tài)的改變而改變,這是我們使用享元模式需要注意的 地方
6) 使用享元模式時,注意劃分內(nèi)部狀態(tài)和外部狀態(tài),并且需要有一個工廠類加以控制。
7) 享元模式經(jīng)典的應用場景是需要緩沖池的場景,比如 String常量池、數(shù)據(jù)庫連接池。
總結
以上是生活随笔為你收集整理的Java设计模式之享元模式(UML类图分析+代码详解)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: qqlive播放器下载视频
- 下一篇: GDUFS 2018信息学院程序设计新手