程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++設計形式之享元形式

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

編輯:關於C++

C++設計形式之享元形式。本站提示廣大學習愛好者:(C++設計形式之享元形式)文章只能為提供參考,不一定能成為您想要的結果。以下是C++設計形式之享元形式正文


媒介

無聊的時刻,也去QQ游戲年夜廳玩五子棋或許象棋;作為法式員,看到一個產物,總要去想一想它是怎樣設計的,怎樣完成的,我想這個是一切法式員都邑做的工作吧(強制症???)。有的時刻,想完了,還要做一個DEMO出來,能力表現本身的NB,然後還有點小造詣感。

在玩五子棋或象棋的時刻,我就想過,騰訊那幫店員是怎樣做的呢?五子棋的棋子有诟谇兩色,豈非每次放一個棋子就new一個對象麼?象棋有車、馬、相、士、帥、炮和兵,是否是每盤棋都要把一切的棋子都new出來呢?假如真的是每個棋子都new一個,那末再加上那末多人玩;那要new若干對象啊,假如是如許做的話,我想有若干辦事器都是弄不定的,能夠QQ游戲年夜廳會比12306還蹩腳。那騰訊那幫店員是若何完成的呢?那就要說到明天總結的享元形式了。

甚麼是享元形式?

在GOF的《設計形式:可復用面向對象軟件的基本》一書中對享元形式是如許說的:應用同享技巧有用地支撐年夜量細粒度的對象。

就如下面說的棋子,假如每一個棋子都new一個對象,就會存在年夜量細粒度的棋子對象,這對辦事器的內存空間是一種考驗,也是一種糟蹋。我們都曉得,好比我在2013號房間和他人下五子棋,2014號房間也有人鄙人五子棋,其實不會由於我在2013號房間,而他人在2014號房間,而招致我們的棋子是紛歧樣的。這就是說,2013號房間和2014號房間的棋子都是一樣的,一切的五子棋房間的棋子都是一樣的。獨一的分歧是每一個棋子在分歧的房間的分歧棋盤的分歧地位上。所以,關於棋子來講,我們不消放一個棋子就new一個棋子對象,只須要在須要的時刻,去要求取得對應的棋子對象,假如沒有,就new一個棋子對象;假如有了,就直接前往棋子對象。這裡以五子棋為例子,停止剖析,當玩家在棋盤上放入第一個白色棋子時,此時因為沒有白色棋子,所以就new一個白色棋子;當另外一個玩家放入第一個黑色棋子時,此時因為沒有黑色棋子,所以就須要new一個黑色棋子;當玩家再次放入一個白色棋子時,就去查詢能否有曾經存在的白色棋子對象,因為第一次曾經new了一個白色棋子對象,所以,如今不會再次new一個白色棋子對象,而是前往之前new的白色棋子對象;關於黑色棋子,亦是同理;取得了棋子對象,我們只須要設置棋子的分歧棋盤地位便可。

UML類圖

Flyweight:描寫一個接口,經由過程這個接口flyweight可以接收並感化於內部狀況;

ConcreteFlyweight:完成Flyweight接口,並為界說了一些外部狀況,ConcreteFlyweight對象必需是可同享的;同時,它所存儲的狀況必需是外部的;即,它必需自力於ConcreteFlyweight對象的場景;

UnsharedConcreteFlyweight:並不是一切的Flyweight子類都須要被同享。Flyweight接口使同享成為能夠,但它其實不強迫同享。

FlyweightFactory:創立並治理flyweight對象。它須要確保公道地同享flyweight;當用戶要求一個flyweight時,FlyweightFactory對象供給一個已創立的實例,假如要求的實例不存在的情形下,就新創立一個實例;

Client:保持一個對flyweight的援用;同時,它須要盤算或存儲flyweight的內部狀況。

完成要點

依據我們的經歷,當要將一個對象停止同享時,就須要斟酌到對象的狀況成績了;分歧的客戶端取得同享的對象以後,能夠會修正同享對象的某些狀況;年夜家都修正了同享對象的狀況,那末就會湧現對象狀況的雜亂。關於享元形式,在完成時必定要斟酌到同享對象的狀況成績。那末享元形式是若何完成的呢?

在享元形式中,有兩個異常主要的概念:外部狀況和內部狀況。

外部狀況存儲於flyweight中,它包括了自力於flyweight場景的信息,這些信息使得flyweight可以被同享。而內部狀況取決於flyweight場景,並依據場景而變更,是以弗成同享。用戶對象擔任在需要的時刻將內部狀況傳遞給flyweight。

flyweight履行時所需的狀況一定是外部的或內部的。外部狀況存儲於ConcreteFlyweight對象當中;而內部對象則由Client對象存儲或盤算。當用戶挪用flyweight對象的操作時,將該狀況傳遞給它。同時,用戶不該該直接對ConcreteFlyweight類停止實例化,而只能從FlyweightFactory對象獲得ConcreteFlyweight對象,這可以包管對它們恰當地停止同享;因為同享一個實例,所以在創立這個實例時,便可以斟酌應用單例形式來停止完成。

享元形式的工場類保護了一個實例列表,這個列表中保留了一切的同享實例;當用戶從享元形式的工場類要求同享對象時,起首查詢這個實例表,假如不存在對應實例,則創立一個;假如存在,則直接前往對應的實例。

代碼完成:


#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;
    }
}

外部狀況包含棋子的色彩,內部狀況包含棋子在棋盤上的地位。終究,我們省去了多個實例對象存儲棋子色彩的空間,從而到達了空間的勤儉。

在下面的代碼中,我樹立了一個CCheseboard用於表現棋盤,棋盤類中保留了放置的黑色棋子和白色棋子;這就相當於在內部保留了同享對象的內部狀況;關於棋盤對象,我們是否是又可使用享元形式呢?再設計一個棋局類停止治理棋盤上的棋子結構,用來保留內部狀況。關於這個,這裡不停止評論辯論了。

長處

享元形式可以免年夜量異常類似對象的開支。在法式設計時,有時須要生成年夜量細粒度的類實例來表現數據。假如能發明這些實例數據除幾個參數外根本都是雷同的,應用享元形式便可以年夜幅度地削減對象的數目。

應用場所

Flyweight形式的有用性很年夜水平上取決於若何應用它和在何處應用它。當以下前提知足時,我們便可以應用享元形式了。

1.一個運用法式應用了年夜量的對象;
2.完整因為應用年夜量的對象,形成很年夜的存儲開支;
3.對象的年夜多半狀況都可變成內部狀況;
4.假如刪除對象的內部狀況,那末可以用絕對較少的同享對象代替許多組對象。

擴大

之前總結了組合形式組合形式,如今回過火來看看,享元形式就比如在組合形式的基本上加上了一個工場類,停止同享掌握。是的,組合形式有的時刻會發生許多細粒度的對象,許多時刻,我們會將享元形式和組合形式停止聯合應用。

總結

應用享元形式可以免年夜量類似對象的開支,減小了空間消費;而空間的消費是由以下幾個身分決議的:

1.實例對象削減的數量;
2.對象外部狀況的數量;對象外部狀況越多,消費的空間也會越少;
3.內部狀況是盤算的照樣存儲的;因為內部狀況能夠須要存儲,假如內部狀況存儲起來,那末空間的節儉就不會太多。

同享的Flyweight越多,存儲勤儉也就越多,勤儉量跟著同享狀況的增多而增年夜。當對象應用年夜量的外部及內部狀況,而且內部狀況是盤算出來的而非存儲的時刻,勤儉量將到達最年夜。所以,可使用兩種辦法來勤儉存儲:用同享削減外部狀況的消費;用盤算時光換取對內部狀況的存儲。

同時,在完成的時刻,必定要掌握好內部狀況與同享對象的對應關系,好比我在代碼完成部門,在CCheseboard類中應用了一個map停止彼此之間的映照,這個映照在現實開辟中須要斟酌的。

好了,享元形式就總結到這裡了。願望年夜家和我分享你對設計形式的懂得。我深信:分享使我們更提高。
PS:至於騰訊那幫店員究竟是若何完成QQ游戲年夜廳的,我也不曉得,這裡也完整是猜想的,請不要以此為基准。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved