歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 設計模式之享元模式——初學

設計模式之享元模式——初學

日期:2017/3/1 9:27:14   编辑:Linux編程

1、引言

一些大型的博客網站、電子商務網站,裡面每一個博客或者商家都可以理解為一個小的網站,他們是如何做到的呢,如何實現同樣的核心代碼,不同的用戶用有不同的效果,實現類型的網站得到復用而不是復制相同的代碼呢?

那些博客網站、電子商務網站是利用用戶ID的不同,來區別不同的用戶,具體的數據和模板可以不同,但代碼核心和數據庫卻是共享的。

假如很多項目到來時,他們需要的網站結構相似度很高,而且都不是那種高訪問量的網站,如果分成多個虛擬空間來處理,相當於一個相同網站的實例對象很多,這是造成服務器的大量資源浪費,當然更實際的其實是鈔票的浪費,如果整合到一個網站中,共享其相關的代碼和數據,那麼對於硬盤、內存、CPU、數據庫空間等服務器資源都可以達到共享,減少服務器資源,而對於代碼,由於是一份實例,維護和擴展都更加容易。

好像很不錯的樣子,我也這麼覺得,那我們就一起來了解一下, 如何做到共享一份實例吧。

2、定義:

享元模式(Flyweight),運用共享技術有效地支持大量細粒度的對象。

3、UML(結構圖)

類解析:

FlyWeightFactory:一個共享工廠,用來創建並管理Flyweight對象。它主要是用來確保合理地共享Flyweight,當用戶請求一個Flyweight是,FlyweightFactory對象提供一個已創建得實例或者創建一個(如果不存在的話)

Flyweight:所有具體享元類的超類或接口,通過這個接口,Flyweight可以接受並作用於外部狀態,

ConcreteFlyweight:繼承Flyweight超類或實現Flyweight接口,並為內部狀態增加存儲空間

UnsharedConcreteFlyweight:指那些不需要共享的Flyweight。因為Flyweight接口共享成為可能,但它不強制要求共享。

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

結果:

Copyright © Linux教程網 All Rights Reserved