欧美大屁股bbbbxxxx,狼人大香伊蕉国产www亚洲,男ji大巴进入女人的视频小说,男人把ji大巴放进女人免费视频,免费情侣作爱视频

歡迎來到入門教程網(wǎng)!

C語言

當前位置:主頁 > 軟件編程 > C語言 >

C++設計模式之享元模式

來源:本站原創(chuàng)|時間:2020-01-10|欄目:C語言|點擊: 次

前言

無聊的時候,也去QQ游戲大廳玩五子棋或者象棋;作為程序員,看到一個產(chǎn)品,總要去想想它是怎么設計的,怎么完成的,我想這個是所有程序員都會做的事情吧(強迫癥???)。有的時候,想完了,還要做一個DEMO出來,才能體現(xiàn)自己的NB,然后還有點小成就感。

在玩五子棋或象棋的時候,我就想過,騰訊那幫伙計是怎么做的呢?五子棋的棋子有黑白兩色,難道每次放一個棋子就new一個對象么?象棋有車、馬、相、士、帥、炮和兵,是不是每盤棋都要把所有的棋子都new出來呢?如果真的是每一個棋子都new一個,那么再加上那么多人玩;那要new多少對象啊,如果是這樣做的話,我想有多少服務器都是搞不定的,可能QQ游戲大廳會比12306還糟糕。那騰訊那幫伙計是如何實現(xiàn)的呢?那就要說到今天總結(jié)的享元模式了。

什么是享元模式?

在GOF的《設計模式:可復用面向?qū)ο筌浖幕A》一書中對享元模式是這樣說的:運用共享技術(shù)有效地支持大量細粒度的對象。

就如上面說的棋子,如果每個棋子都new一個對象,就會存在大量細粒度的棋子對象,這對服務器的內(nèi)存空間是一種考驗,也是一種浪費。我們都知道,比如我在2013號房間和別人下五子棋,2014號房間也有人在下五子棋,并不會因為我在2013號房間,而別人在2014號房間,而導致我們的棋子是不一樣的。這就是說,2013號房間和2014號房間的棋子都是一樣的,所有的五子棋房間的棋子都是一樣的。唯一的不同是每個棋子在不同的房間的不同棋盤的不同位置上。所以,對于棋子來說,我們不用放一個棋子就new一個棋子對象,只需要在需要的時候,去請求獲得對應的棋子對象,如果沒有,就new一個棋子對象;如果有了,就直接返回棋子對象。這里以五子棋為例子,進行分析,當玩家在棋盤上放入第一個白色棋子時,此時由于沒有白色棋子,所以就new一個白色棋子;當另一個玩家放入第一個黑色棋子時,此時由于沒有黑色棋子,所以就需要new一個黑色棋子;當玩家再次放入一個白色棋子時,就去查詢是否有已經(jīng)存在的白色棋子對象,由于第一次已經(jīng)new了一個白色棋子對象,所以,現(xiàn)在不會再次new一個白色棋子對象,而是返回以前new的白色棋子對象;對于黑色棋子,亦是同理;獲得了棋子對象,我們只需要設置棋子的不同棋盤位置即可。

UML類圖

Flyweight:描述一個接口,通過這個接口flyweight可以接受并作用于外部狀態(tài);

ConcreteFlyweight:實現(xiàn)Flyweight接口,并為定義了一些內(nèi)部狀態(tài),ConcreteFlyweight對象必須是可共享的;同時,它所存儲的狀態(tài)必須是內(nèi)部的;即,它必須獨立于ConcreteFlyweight對象的場景;

UnsharedConcreteFlyweight:并非所有的Flyweight子類都需要被共享。Flyweight接口使共享成為可能,但它并不強制共享。

FlyweightFactory:創(chuàng)建并管理flyweight對象。它需要確保合理地共享flyweight;當用戶請求一個flyweight時,F(xiàn)lyweightFactory對象提供一個已創(chuàng)建的實例,如果請求的實例不存在的情況下,就新創(chuàng)建一個實例;

Client:維持一個對flyweight的引用;同時,它需要計算或存儲flyweight的外部狀態(tài)。

實現(xiàn)要點

根據(jù)我們的經(jīng)驗,當要將一個對象進行共享時,就需要考慮到對象的狀態(tài)問題了;不同的客戶端獲得共享的對象之后,可能會修改共享對象的某些狀態(tài);大家都修改了共享對象的狀態(tài),那么就會出現(xiàn)對象狀態(tài)的紊亂。對于享元模式,在實現(xiàn)時一定要考慮到共享對象的狀態(tài)問題。那么享元模式是如何實現(xiàn)的呢?

在享元模式中,有兩個非常重要的概念:內(nèi)部狀態(tài)和外部狀態(tài)。

內(nèi)部狀態(tài)存儲于flyweight中,它包含了獨立于flyweight場景的信息,這些信息使得flyweight可以被共享。而外部狀態(tài)取決于flyweight場景,并根據(jù)場景而變化,因此不可共享。用戶對象負責在必要的時候?qū)⑼獠繝顟B(tài)傳遞給flyweight。

flyweight執(zhí)行時所需的狀態(tài)必定是內(nèi)部的或外部的。內(nèi)部狀態(tài)存儲于ConcreteFlyweight對象之中;而外部對象則由Client對象存儲或計算。當用戶調(diào)用flyweight對象的操作時,將該狀態(tài)傳遞給它。同時,用戶不應該直接對ConcreteFlyweight類進行實例化,而只能從FlyweightFactory對象得到ConcreteFlyweight對象,這可以保證對它們適當?shù)剡M行共享;由于共享一個實例,所以在創(chuàng)建這個實例時,就可以考慮使用單例模式來進行實現(xiàn)。

享元模式的工廠類維護了一個實例列表,這個列表中保存了所有的共享實例;當用戶從享元模式的工廠類請求共享對象時,首先查詢這個實例表,如果不存在對應實例,則創(chuàng)建一個;如果存在,則直接返回對應的實例。

代碼實現(xiàn):

復制代碼 代碼如下:

#include <iostream>
#include <map>
#include <vector>
using namespace std;
 
typedef struct pointTag
{
    int x;
    int y;
 
    pointTag(){}
    pointTag(int a, int b)
    {
        x = a;
        y = b;
    }
 
     bool operator <(const pointTag& other) const
     {
         if (x < other.x)
         {
             return true;
         }
         else if (x == other.x)
         {
             return y < other.y;
         }
 
         return false;
     }
}POINT;
 
typedef enum PieceColorTag
{
    BLACK,
    WHITE
}PIECECOLOR;
 
class CPiece
{
public:
    CPiece(PIECECOLOR color) : m_color(color){}
    PIECECOLOR GetColor() { return m_color; }
 
    // Set the external state
    void SetPoint(POINT point) { m_point = point; }
    POINT GetPoint() { return m_point; }
 
protected:
    // Internal state
    PIECECOLOR m_color;
 
    // external state
    POINT m_point;
};
 
class CGomoku : public CPiece
{
public:
    CGomoku(PIECECOLOR color) : CPiece(color){}
};
 
class CPieceFactory
{
public:
    CPiece *GetPiece(PIECECOLOR color)
    {
        CPiece *pPiece = NULL;
        if (m_vecPiece.empty())
        {
            pPiece = new CGomoku(color);
            m_vecPiece.push_back(pPiece);
        }
        else
        {
            bool bFound = false; // 非常感謝fireace指出的問題
            for (vector<CPiece *>::iterator it = m_vecPiece.begin(); it != m_vecPiece.end(); ++it)
            {
                if ((*it)->GetColor() == color)
                {
                    bFound = true;
                    pPiece = *it;
                    break;
                }
                bFound = false;
            }
            if (!bFound)
            {
                pPiece = new CGomoku(color);
                m_vecPiece.push_back(pPiece);
            }
        }
        return pPiece;
    }
 
    ~CPieceFactory()
    {
        for (vector<CPiece *>::iterator it = m_vecPiece.begin(); it != m_vecPiece.end(); ++it)
        {
            if (*it != NULL)
            {
                delete *it;
                *it = NULL;
            }
        }
    }
 
private:
    vector<CPiece *> m_vecPiece;
};
 
class CChessboard
{
public:
    void Draw(CPiece *piece)
    {
        if (piece->GetColor())
        {
            cout<<"Draw a White"<<" at ("<<piece->GetPoint().x<<","<<piece->GetPoint().y<<")"<<endl;
        }
        else
        {
            cout<<"Draw a Black"<<" at ("<<piece->GetPoint().x<<","<<piece->GetPoint().y<<")"<<endl;
        }
        m_mapPieces.insert(pair<POINT, CPiece *>(piece->GetPoint(), piece));
    }
 
    void ShowAllPieces()
    {
        for (map<POINT, CPiece *>::iterator it = m_mapPieces.begin(); it != m_mapPieces.end(); ++it)
        {
            if (it->second->GetColor())
            {
                cout<<"("<<it->first.x<<","<<it->first.y<<") has a White chese."<<endl;
            }
            else
            {
                cout<<"("<<it->first.x<<","<<it->first.y<<") has a Black chese."<<endl;
            }
        }
    }
 
private:
    map<POINT, CPiece *> m_mapPieces;
};
 
int main()
{
    CPieceFactory *pPieceFactory = new CPieceFactory();
    CChessboard *pCheseboard = new CChessboard();
 
    // The player1 get a white piece from the pieces bowl
    CPiece *pPiece = pPieceFactory->GetPiece(WHITE);
    pPiece->SetPoint(POINT(2, 3));
    pCheseboard->Draw(pPiece);
 
    // The player2 get a black piece from the pieces bowl
    pPiece = pPieceFactory->GetPiece(BLACK);
    pPiece->SetPoint(POINT(4, 5));
    pCheseboard->Draw(pPiece);
 
    // The player1 get a white piece from the pieces bowl
    pPiece = pPieceFactory->GetPiece(WHITE);
    pPiece->SetPoint(POINT(2, 4));
    pCheseboard->Draw(pPiece);
 
    // The player2 get a black piece from the pieces bowl
    pPiece = pPieceFactory->GetPiece(BLACK);
    pPiece->SetPoint(POINT(3, 5));
    pCheseboard->Draw(pPiece);
 
    /*......*/
 
    //Show all cheses
    cout<<"Show all cheses"<<endl;
    pCheseboard->ShowAllPieces();
 
    if (pCheseboard != NULL)
    {
        delete pCheseboard;
        pCheseboard = NULL;
    }
    if (pPieceFactory != NULL)
    {
        delete pPieceFactory;
        pPieceFactory = NULL;
    }
}

內(nèi)部狀態(tài)包括棋子的顏色,外部狀態(tài)包括棋子在棋盤上的位置。最終,我們省去了多個實例對象存儲棋子顏色的空間,從而達到了空間的節(jié)約。

在上面的代碼中,我建立了一個CCheseboard用于表示棋盤,棋盤類中保存了放置的黑色棋子和白色棋子;這就相當于在外部保存了共享對象的外部狀態(tài);對于棋盤對象,我們是不是又可以使用享元模式呢?再設計一個棋局類進行管理棋盤上的棋子布局,用來保存外部狀態(tài)。對于這個,這里不進行討論了。

優(yōu)點

享元模式可以避免大量非常相似對象的開銷。在程序設計時,有時需要生成大量細粒度的類實例來表示數(shù)據(jù)。如果能發(fā)現(xiàn)這些實例數(shù)據(jù)除了幾個參數(shù)外基本都是相同的,使用享元模式就可以大幅度地減少對象的數(shù)量。

使用場合

Flyweight模式的有效性很大程度上取決于如何使用它以及在何處使用它。當以下條件滿足時,我們就可以使用享元模式了。

1.一個應用程序使用了大量的對象;
2.完全由于使用大量的對象,造成很大的存儲開銷;
3.對象的大多數(shù)狀態(tài)都可變?yōu)橥獠繝顟B(tài);
4.如果刪除對象的外部狀態(tài),那么可以用相對較少的共享對象取代很多組對象。

擴展

之前總結(jié)了組合模式組合模式,現(xiàn)在回過頭來看看,享元模式就好比在組合模式的基礎上加上了一個工廠類,進行共享控制。是的,組合模式有的時候會產(chǎn)生很多細粒度的對象,很多時候,我們會將享元模式和組合模式進行結(jié)合使用。

總結(jié)

使用享元模式可以避免大量相似對象的開銷,減小了空間消耗;而空間的消耗是由以下幾個因素決定的:

1.實例對象減少的數(shù)目;
2.對象內(nèi)部狀態(tài)的數(shù)目;對象內(nèi)部狀態(tài)越多,消耗的空間也會越少;
3.外部狀態(tài)是計算的還是存儲的;由于外部狀態(tài)可能需要存儲,如果外部狀態(tài)存儲起來,那么空間的節(jié)省就不會太多。

共享的Flyweight越多,存儲節(jié)約也就越多,節(jié)約量隨著共享狀態(tài)的增多而增大。當對象使用大量的內(nèi)部及外部狀態(tài),并且外部狀態(tài)是計算出來的而非存儲的時候,節(jié)約量將達到最大。所以,可以使用兩種方法來節(jié)約存儲:用共享減少內(nèi)部狀態(tài)的消耗;用計算時間換取對外部狀態(tài)的存儲。

同時,在實現(xiàn)的時候,一定要控制好外部狀態(tài)與共享對象的對應關系,比如我在代碼實現(xiàn)部分,在CCheseboard類中使用了一個map進行彼此之間的映射,這個映射在實際開發(fā)中需要考慮的。

好了,享元模式就總結(jié)到這里了。希望大家和我分享你對設計模式的理解。我堅信:分享使我們更進步。
PS:至于騰訊那幫伙計到底是如何實現(xiàn)QQ游戲大廳的,我也不知道,這里也完全是猜測的,請不要以此為基準。

上一篇:C++設計模式之觀察者模式

欄    目:C語言

下一篇:C++中的類型轉(zhuǎn)換static_cast、dynamic_cast、const_cast和reinterpret_cas

本文標題:C++設計模式之享元模式

本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/3306.html

網(wǎng)頁制作CMS教程網(wǎng)絡編程軟件編程腳本語言數(shù)據(jù)庫服務器

如果侵犯了您的權(quán)利,請與我們聯(lián)系,我們將在24小時內(nèi)進行處理、任何非本站因素導致的法律后果,本站均不負任何責任。

聯(lián)系QQ:835971066 | 郵箱:835971066#qq.com(#換成@)

Copyright © 2002-2020 腳本教程網(wǎng) 版權(quán)所有