1、引言
一些大型的博客網站、電子商務網站,里面每一個博客或者商家都可以理解為一個小的網站,他們是如何做到的呢,如何實現同樣的核心代碼,不同的用戶用有不同的效果,實現類型的網站得到復用而不是復制相同的代碼呢?
那些博客網站、電子商務網站是利用用戶ID的不同,來區別不同的用戶,具體的數據和模板可以不同,但代碼核心和數據庫卻是共享的。
假如很多項目到來時,他們需要的網站結構
相似度很高,而且都
不是那種高訪問量的網站,如果分成多個虛擬空間來處理,相當於一個相同網站的實例對象很多,這是造成服務器的大量資源浪費,當然更實際的其實是鈔票的浪費,如果整合到一個網站中,共享其相關的代碼和數據,那么對於硬盤、內存、CPU、數據庫空間等服務器資源都可以達到共享,減少服務器資源,而對於代碼,由於是一份實例,維護和擴展都更加容易。
好像很不錯的樣子,我也這么覺得,那我們就一起來了解一下, 如何做到共享一份實例吧。
2、定義:
享元模式(Flyweight),運用共享技術有效地支持大量細粒度的對象。
|
3、UML(結構圖)


類解析:
|
4、實踐
網站共享代碼
package com.zcr.flyweight; //享元設計模式實現 //網站抽象類 public abstract class WebSite { public abstract void Use(); }
package com.zcr.flyweight; //具體的網站類 public class ConcreteWebSite extends WebSite { private String name = ""; public ConcreteWebSite(String name) { this.name = name; } @Override public void Use() { System.out.println("網站分類:"+name); } }
package com.zcr.flyweight; import java.util.Hashtable; //網站工廠 public class WebsiteFactory { private Hashtable<String,WebSite> flyweights = new Hashtable<String, WebSite>(); //獲得網站分類 public WebSite GetWebSiteCategory(String key) { //判斷是否存在這個對象,如果存在則直接返回,若不存在,則實例化它再返回 if(!flyweights.contains(key)) { flyweights.put(key, new ConcreteWebSite(key)); } return flyweights.get(key); } //獲取網站分類的總數 public int GetWebSiteCount() { return flyweights.size(); } }
package com.zcr.flyweight; public class FlyweightTest { public static void main(String[] args) { WebsiteFactory f = new WebsiteFactory(); WebSite fx = f.GetWebSiteCategory("產品展示"); fx.Use(); WebSite fy = f.GetWebSiteCategory("產品展示"); fy.Use(); WebSite fz = f.GetWebSiteCategory("產品展示"); fz.Use(); WebSite fl = f.GetWebSiteCategory("博客"); fl.Use(); WebSite fm = f.GetWebSiteCategory("博客"); fm.Use(); WebSite fn = f.GetWebSiteCategory("博客"); fn.Use(); System.out.println("網站分類總數為:" + f.GetWebSiteCount()); } }
結果:
上面只實現了對象的共享,不管建立幾個網站,是要是‘產品展示’都好是一樣的的,只要是‘博客’也是完全相同的,但這樣是有問題的,你給企業建立的網站不是一家企業,它們的數據不會相同,所以至少它們應該有不同的賬號,那我們該怎么辦呢?
概念:
內部狀態:在享元內部並且不會隨環境改變而改變的共享部分
外部狀態:隨環境改變而改變的、不可能共享的狀態就是外部狀態
|
享元模式可以避免大量非常相似類的開銷,在程序設計中,有時需喲生成大量細粒度的類實例來表示數據,如果能發現這些實例除了幾個參數外基本上都是相同的,有時就能夠大幅度的減少需要實例化類的數量。如果能把那些參數移到類實例的外面,在方法調用時將它們傳進來,就可以通過共享大幅度地減少單個實例的數目。也就是說,享元模式Flyweight執行時所需要的狀態有內部的也有外部的,內部狀態存儲於ConcreteFlyweight對象之中,而外部對象則應該考慮由客戶端對象存儲或計算,當調用Flyweight對象的操作時,將該狀態傳遞給它。
應用場景
如果一個應用程序使用了大量的對象,而大量的這些對象造成了很大的存儲開銷時就應該考慮使用;還有就是對象的大多數狀態可以外部狀態,如果刪除對象的外部狀態,那么可以用相對較少的共享對象取代很多組對象,此時可以考慮使用享元模式。
|
java的String就是采用了這種方式。
package com.zcr.flyweight2; public class User { private String name; public User(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
package com.zcr.flyweight2; //享元設計模式實現 //網站抽象類 public abstract class WebSite { //“使用”方法需要傳遞“用戶”對象 public abstract void Use(User user); }
package com.zcr.flyweight2; //具體的網站類 public class ConcreteWebSite extends WebSite { private String name = ""; public ConcreteWebSite(String name) { this.name = name; } @Override public void Use(User user) { System.out.println("網站分類:"+name+"用戶名:"+user.getName()); } }
package com.zcr.flyweight2; import java.util.Hashtable; //網站工廠 public class WebsiteFactory { private Hashtable<String,WebSite> flyweights = new Hashtable<String, WebSite>(); //獲得網站分類 public WebSite GetWebSiteCategory(String key) { //判斷是否存在這個對象,如果存在則直接返回,若不存在,則實例化它再返回 if(!flyweights.contains(key)) { flyweights.put(key, new ConcreteWebSite(key)); } return flyweights.get(key); } //獲取網站分類的總數 public int GetWebSiteCount() { return flyweights.size(); } }
package com.zcr.flyweight2; public class FlyweightTest { public static void main(String[] args) { WebsiteFactory f = new WebsiteFactory(); WebSite fx = f.GetWebSiteCategory("產品展示"); fx.Use(new User("小菜")); WebSite fy = f.GetWebSiteCategory("產品展示"); fy.Use(new User("大煙籠")); WebSite fz = f.GetWebSiteCategory("產品展示"); fz.Use(new User("大菜")); WebSite fl = f.GetWebSiteCategory("博客"); fl.Use(new User("老頑童")); WebSite fm = f.GetWebSiteCategory("博客"); fm.Use(new User("肥菜")); WebSite fn = f.GetWebSiteCategory("博客"); fn.Use(new User("小小斌")); System.out.println("網站分類總數為:" + f.GetWebSiteCount()); } }
結果: