• 设计模式之享元(flyweight)模式


      现在在大力推行节约型社会,“浪费可耻,节俭光荣”。在软件系统中,有时候也会存在资源浪费的情况,例如,在计算机内存中存储了多个完全相同或者非常相似的对象,如果这些对象的数量太多将导致系统运行代价过高。那么,是否存在一种技术可以用于节约内存使用空间,实现对这些相同或者相似对象的共享访问呢?答案是肯定的,这种技术就是享元模式。

    一 享元模式概述

    1.1 享元模式简介

    享元(Flyweight)模式:运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,是一种结构型模式。

    1.2 享元模式需求

      M公司开发部欲开发一个围棋软件,其界面效果如下图所示:

      M公司开发人员通过对围棋软件进行分析,发现在围棋棋盘中包含大量的黑子和白子,它们的形状、大小都一模一样,只是出现的位置不同而已。如果将每一个棋子都作为一个独立的对象存储在内存中,将可能导致该围棋软件在运行时所需要的内存空间较大。

      如何降低运行代价、提高系统性能是M公司开发人员需要解决的一个问题。为此,M公司开发人员决定使用享元模式来设计该软件。

    1.3 类图

      

    1.4 代码实现

    1.4.1 抽象棋子类

    #pragma once
    
    #include <string>
    #include <iostream>
    using namespace std;
    class AbstractPiece
    {
    public:
        AbstractPiece(){}
        ~AbstractPiece(){}
    
        virtual string GetColor() = 0;
        virtual void Display(CCoordinates *pCoodinates) = 0;
    };

    1.4.2 白色棋子类

    class WritePiece : public AbstractPiece
    {
    public:
        WritePiece()
        {
            cout << "WritePiece Construct" << endl;
        }
        ~WritePiece()
        {
            cout << "WritePiece Deconstruct" << endl;
        }
    
        string GetColor()
        {
            return "white";
        }
    
        void Display(CCoordinates *pCoodinates)
        {
            cout << "棋子颜色:"<< GetColor() << "," << 
                "棋子坐标:" << pCoodinates->m_x << "," << pCoodinates->m_y << endl;
        }
    };

    1.4.5 黑色棋子类

    class BlackPiece : public AbstractPiece
    {
    public:
        BlackPiece()
        {
            cout << "BlackPiece Construct" << endl;
        }
        ~BlackPiece()
        {
            cout << "BlackPiece Deconstruct" << endl;
        }
    
        string GetColor()
        {
            return "black";
        }
    
        void Display(CCoordinates *pCoodinates)
        {
            cout << "棋子颜色:"<< GetColor() << "," << 
                "棋子坐标:" << pCoodinates->m_x << "," << pCoodinates->m_y << endl;
        }
    };

    1.4.6 棋子外部状态类

    class CCoordinates
    {
    public:
        CCoordinates(int x, int y)
        {
            m_x = x;
            m_y = y;
        }
        ~CCoordinates(){}
    
    public:
        int m_x;
        int m_y;
    };

    1.4.7 棋子工厂类(单例)

    #pragma once
    
    #include "flyweight.h"
    #include <map>
    using namespace std;
    
    class CPieceFactor
    {
    private:
        CPieceFactor();
        ~CPieceFactor();
    
    public:
        //static CPieceFactor* GetPieceFactorInstance();
        static AbstractPiece* CreatePiece( string strColor );
    private:
        typedef map<string, AbstractPiece*> PIECEMAP;
        static PIECEMAP m_PieceVect;
        static CPieceFactor *m_pPieceFactor;
    };
    #include "PieceFactor.h"
    
    // 饥饿模式的单例模式
    CPieceFactor::PIECEMAP CPieceFactor::m_PieceVect;
    CPieceFactor * CPieceFactor::m_pPieceFactor = new CPieceFactor();
    CPieceFactor::CPieceFactor()
    {
        AbstractPiece *pWrite = new WritePiece();
        m_PieceVect.insert(make_pair<string, AbstractPiece*>("write", pWrite));
        AbstractPiece *pBlack = new BlackPiece();
        m_PieceVect.insert(make_pair<string, AbstractPiece*>("black", pBlack));
    }
    
    CPieceFactor::~CPieceFactor()
    {
        PIECEMAP::iterator iter;
        for (iter = m_PieceVect.begin(); iter != m_PieceVect.end(); iter ++)
        {
            delete iter->second;
        }
    }
    
    AbstractPiece* CPieceFactor::CreatePiece( string strColor )
    {
        return m_PieceVect[strColor];
    }

    1.5 测试

    #include "stdio.h"
    
    #include "PieceFactor.h"
    
    void main()
    {
        // 通过享元工厂获取3颗黑子
        AbstractPiece *pPiece1 = CPieceFactor::CreatePiece("black");
        AbstractPiece *pPiece2 = CPieceFactor::CreatePiece("black");
        AbstractPiece *pPiece3 = CPieceFactor::CreatePiece("black");
    
        string strCmp;
        strCmp = pPiece1 == pPiece2 ? "相同":"不相同";
        cout << "判断两颗黑子是否相同:" << strCmp.c_str() <<endl;
    
         // 通过享元工厂获取2颗白子
        AbstractPiece *pPiece4 = CPieceFactor::CreatePiece("write");
        AbstractPiece *pPiece5 = CPieceFactor::CreatePiece("write");
        strCmp = pPiece1 == pPiece2 ? "相同":"不相同";
        cout << "判断两颗白字是否相同:" << strCmp.c_str() <<endl;
        
        // 显示棋子
        pPiece1->Display(new CCoordinates(1,2));
        pPiece2->Display(new CCoordinates(3, 4));
        pPiece3->Display(new CCoordinates(1, 3));
        pPiece4->Display(new CCoordinates(2, 5));
        pPiece5->Display(new CCoordinates(2, 4));
    
        return;
    }

    二 享元模式总结

    2.1 主要优点

      可以极大减少内存中对象的数量,使得相同或相似对象在内存中只有一份 => 节省系统资源,提高系统性能!棒棒哒!

    2.2 主要缺点

      为了使对象可以共享,享元模式需要将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长!

    2.3 应用场景

      (1)一个系统有大量相同或相似的对象,造成了系统内存的大量损耗 => 赶紧使用享元模式吧!

      (2)对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。

      (3)要维护享元模式,需要耗费一定的系统资源,因为在需要时会多次重复使用才值得使用享元模式了!

  • 相关阅读:
    [BJWC2010]外星联络
    [NOI2015]品酒大会
    工艺 /【模板】最小表示法
    [NOI2016]优秀的拆分
    [HEOI2016/TJOI2016]字符串
    [SDOI2016]生成魔咒
    【模板】后缀自动机 (SAM)【SA解法】
    [湖南集训]图森
    [USACO17DEC]Standing Out from the Herd P
    Annihilate
  • 原文地址:https://www.cnblogs.com/xiaobingqianrui/p/9023602.html
Copyright © 2020-2023  润新知