享元模式

1. 項目也別傻作

A: 三個做品展現,三個博客,其實它們本質上都是同樣的代碼。
B: 共用一套代碼,可是畢竟是不一樣的網站,數據都不相同。
A: 共享代碼,爲何不能夠呢?好比如今大型的網站,裏面的一個博客或商家也能夠理解爲一個個小的網站,但它們是如何作的?
B: 利用ID的不一樣,來區分不一樣的用戶,具體數據和模版都是不一樣,可是代碼核心和數據庫倒是共享的。數據庫

2. 享元模式

運用共享技術有效的支持大量細粒度的對象。

圖2

class Program
{
    static void Main(string[] args)
    {
        int extrinsicstate = 22;

        FlyweightFactory f = new FlyweightFactory();

        Flyweight fx = f.GetFlyweight("X");
        fx.Operation(--extrinsicstate);

        Flyweight fy = f.GetFlyweight("Y");
        fy.Operation(--extrinsicstate);

        Flyweight fz = f.GetFlyweight("Z");
        fz.Operation(--extrinsicstate);

        UnsharedConcreteFlyweight uf = new UnsharedConcreteFlyweight();

        uf.Operation(--extrinsicstate);

        Console.Read();
    }
}

class FlyweightFactory
{
    private Hashtable flyweights = new Hashtable();

    public FlyweightFactory()
    {
        flyweights.Add("X", new ConcreteFlyweight());
        flyweights.Add("Y", new ConcreteFlyweight());
        flyweights.Add("Z", new ConcreteFlyweight());

    }

    public Flyweight GetFlyweight(string key)
    {
        return ((Flyweight)flyweights[key]);
    }
}

abstract class Flyweight
{
    public abstract void Operation(int extrinsicstate);
}

class ConcreteFlyweight : Flyweight
{
    public override void Operation(int extrinsicstate)
    {
        Console.WriteLine("具體Flyweight:" + extrinsicstate);
    }
}

class UnsharedConcreteFlyweight : Flyweight
{
    public override void Operation(int extrinsicstate)
    {
        Console.WriteLine("不共享的具體Flyweight:" + extrinsicstate);
    }
}

B: FlyweightFactory根據客戶需求返回早已生成好的對象,但必定要事先生成對象實例嗎?
A: 其實是不必定須要,徹底能夠初始化時什麼都不作,到須要時,再去判斷對象是否爲null來決定是否實例化。
A: UnsharedConcreteFlyweight子類解決那些不須要共享對象的問題。設計模式

3. 網站共享代碼

class Program
{
    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();

        Console.WriteLine("網站分類總數爲 {0}", f.GetWebSiteCount());

        Console.Read();
    }
}

//網站工廠
class WebSiteFactory
{
    private Hashtable flyweights = new Hashtable();

    //得到網站分類
    public WebSite GetWebSiteCategory(string key)
    {
        if (!flyweights.ContainsKey(key))
            flyweights.Add(key, new ConcreteWebSite(key));
        return ((WebSite)flyweights[key]);
    }

    //得到網站分類總數
    public int GetWebSiteCount()
    {
        return flyweights.Count;
    }
}

//網站
abstract class WebSite
{
    public abstract void Use();
}

//具體的網站
class ConcreteWebSite : WebSite
{
    private string name = "";
    public ConcreteWebSite(string name)
    {
        this.name = name;
    }

    public override void Use()
    {
        Console.WriteLine("網站分類:" + name);
    }
}

A: 這樣有個問題,你給企業建的網站不是一家的企業,它們的數據不會相同,全部至少它們都應該有不一樣的賬號,你怎麼辦?
B: 時間上,上面的代碼沒有體現對象間的不一樣,只體現了它們的共享部分。數組

4. 內部狀態與外部狀態

A: 在享元對象內部而且不會隨環境改變而改變的共享部分,能夠稱爲享元對象的內部狀態,而隨着環境改變而改變,不能夠共享的就是外部狀態。事實上,享元模式能夠避免大量很是類似類的開銷。在程序設計中,有時須要生成大量細粒度的類實例來表示數據。若是能發現這些實例除了幾個參數外基本相同,有時可以大幅度的減小須要實例化的類的數量。若是能把那些參數移到類實例外面,在方法調用將它們傳遞進來,就能夠經過共享大幅度地減小單個實例的數目。內部狀態存儲於ConcreteFlyweight對象之中,而外部對象則應該考慮有客戶端對象存儲或計算,當調用Flyweight對象的操做時,將該狀態傳遞給它。
B: 那你的意識是說,客戶的帳號是外部狀態,應該由專門的對象來處理。
圖2ide

class Program
{
    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("南海鱷神"));

        Console.WriteLine("獲得網站分類總數爲 {0}", f.GetWebSiteCount());

        //string titleA = "大話設計模式";
        //string titleB = "大話設計模式";

        //Console.WriteLine(Object.ReferenceEquals(titleA, titleB));


        Console.Read();
    }
}

//用戶
public class User
{
    private string name;

    public User(string name)
    {
        this.name = name;
    }

    public string Name
    {
        get { return name; }
    }
}


//網站工廠
class WebSiteFactory
{
    private Hashtable flyweights = new Hashtable();

    //得到網站分類
    public WebSite GetWebSiteCategory(string key)
    {
        if (!flyweights.ContainsKey(key))
            flyweights.Add(key, new ConcreteWebSite(key));
        return ((WebSite)flyweights[key]);
    }

    //得到網站分類總數
    public int GetWebSiteCount()
    {
        return flyweights.Count;
    }
}

//網站
abstract class WebSite
{
    public abstract void Use(User user);
}

//具體的網站
class ConcreteWebSite : WebSite
{
    private string name = "";
    public ConcreteWebSite(string name)
    {
        this.name = name;
    }

    public override void Use(User user)
    {
        Console.WriteLine("網站分類:" + name + " 用戶:" + user.Name);
    }
}

5. 享元模式應用

A: 若是一個應用程序使用了大量的對象,而大量的這些對象形成了很大的開銷時就應該考慮使用,還有就是對象的大多數狀態能夠外部狀態,若是刪除對象的外部狀態,那麼能夠用相對較小的共享對象取代不少組對象,此時能夠考慮使用享元模式。
A: 雖然說享元模式更多的時候是一種底層的設計模式(數組,字符串共享),但現實也是有應用的。好比說休閒遊戲開放,想圍棋,五子棋等,它們都有大量的棋子對象,它們的內部狀態和外部狀態?
B: 顏色是內部狀態和座標是棋子的外部狀態。
A: 享元模式須要維護一個記錄了系統已有的全部享元列表,而這自己須要耗費資源,另外享元模式使得系統更加複雜。爲了使對象能夠共享,須要將一些狀態外部化,這使得程序的邏輯複雜化。所以,應當在有足夠的對象實例可工共享時才值得使用享元模式。網站

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息