亨元模式 结构型模式之六

1.定义

        享元模式是一种结构型设计模式, 它允许你在消耗少量内存的情况下支持大量对象。

2.滑滑梯问题

        在说明亨元模式之前,我们先看看关于滑滑梯的程序设计。小区的楼下只有三个滑滑梯,但是想玩的小朋友却非常多。怎么设计计滑滑梯资源的管理,避免小朋友使用滑滑梯的时发生冲突呢。(这里我们设定每个滑滑梯每次仅能供一个小朋友玩耍)。解决这个问题,我们就可以使用享元模式(Flyweight),它就是运用共享技术有效的支持大量细粒度的对象

        怎么理解大量细粒度的对象呢?我一开始理解亨元模式的时候其实对这个概念理解的并不清楚。就滑滑梯这个问题,大家认为大量细粒度对象是滑滑梯还是小朋友呢?如果这个问题回答的不好,那么说明你对亨元模式还是不够了解。这里我直接给出答案,大量细粒度的对象指的是滑滑梯。有朋友会很疑惑,滑滑梯我们不是设定有三个么?怎么是大量细粒度对象,哪儿来的大量。其实这个问题逻辑很简单,我们假设有一百个小朋友要玩滑滑梯,那事实上我们只要造一百个滑滑梯就好了,对么。但现实是,我们并没有那么蠢,我们让小朋友排着队轮流玩就好了。三个滑滑梯事实上是果,是采用了亨元模式的果,已经是亨元模式优化过的情况。如果没有亨元模式,那么我们确实要造一百个滑滑梯,每个小朋友专属一个。

3.实现思路

        如果不对滑滑梯的资源进行管理,可能会出现这个情况:小朋友们在使用滑滑梯时,并考虑当前滑滑梯是否被使用。很可能两个小朋友同时使用一个滑滑梯,导致冲突,不符合预期。所以我们重点是要对滑滑梯的资源使用进行有效的管理,比如这时候有一个大人来维护滑滑梯的使用秩序。大人作为三个滑滑梯的管理员,小朋友们使用滑滑梯需要向他提出申请,得到准许之后才能玩。经过大人管理之后的滑滑梯使用会变成这个情况:小朋友们排队申请滑滑梯的使用权限,大人根据滑滑梯的现有使用状况,如果还有滑滑梯上没有小朋友玩耍,那么可以提供该滑滑梯给小朋友,如果滑滑梯全部被使用则小朋友申请资源失败,需要继续等待。

        我们进一步假设,加入这时候小区其实存在若干个备用的充气滑滑梯,而且小区虽然有一百个小朋友,但他们并不是同时都在楼下玩的。这个时候整个系统就是一个动态的过程。只要有小朋友申请玩滑滑梯,管理员有限在现有的滑滑梯资源里找,如果有空闲的滑滑梯就会提供给当前申请的小朋友,如果没有那么就(新建资源)使用备用的充气滑滑梯。如果连备用的充气滑滑梯都用完了,这就已经触及到系统的资源上限了(内存上限),还是需要排队。

        总而言之,恒元模式就是解决需要为一个小朋友定制一个滑滑梯的问题。通过共享资源池来达到相同的目的。

4.组成结构         

  1. 抽象享元:为具体享元角色规定了必须实现的方法,而外部状态就是以参数的形式通过此方法传入。(滑滑梯)
  2. 具体享元:实现抽象角色规定的方法。如果存在内部状态,就负责为内在部状态提供存储空间。(社区里具体的滑滑梯)
  3. 享元工厂角色:负责创建和管理享元角色。要想达到共享的目的,这个角色的实现是关键!(管理员)
  4. 客户端角色:维护对所有享元对象的引用,而且还需要存储对应的外部状态。 (小朋友)

内部状态,就是各个对象不会随着环境的改变而改变的可共享部分;(滑梯本身)

外部状态,指对象随环境改变而改变的不可以共享的部分。内部状态和外部状态彼此互不影响,改变其中一个并不会改变另一个的行为。(滑梯使用者)。

享元模式将享元对象的状态外部化,而读取外部状态可能使得运行时间稍微变长。

5.示例代码

#include <iostream>
#include<string>
#include<map>
using namespace std;

//客户端类
class Kid
{
private:
    string m_name;
public:
    Kid(string name)
    {
        m_name = name;
    }
    std::string GetName()
    {
        return m_name;
    }
};

//抽象亨元类(滑滑梯)
class Slide
{
public:
    virtual ~Slide() = default;
    virtual void Use(Kid user) = 0;
};

//具体亨元类(小区的滑滑梯)
class ConcreteSlide :public Slide
{
private:
    string m_id;
public:
    ConcreteSlide(std::string id)
    {
        m_id = id;
    }
    void Use(Kid user)override
    {
        cout << "滑滑梯:" << m_id << "  小朋友:" + user.GetName() << endl;
    }
};

//滑滑梯管理员
//如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。
class SlideFactory
{
private:
    std::map<std::string, Slide*> flyweights;
public:
    ~SlideFactory()
    {
        for (auto it = flyweights.begin(); it != flyweights.end(); ++it)
            delete it->second;
    }
    Slide* GetSlideCategory(string key)
    {
        for (auto it = flyweights.begin(); it != flyweights.end(); ++it)
        {
            if (it->first == key)
                return it->second;
        }

        Slide* slide = new ConcreteSlide(key);
        flyweights.insert(pair<std::string, Slide*>(key, slide));
        return slide;
    }
    int GetSlideCount()
    {
        return flyweights.size();
    }
};

int main()
{
    SlideFactory f;

    Slide* fx = f.GetSlideCategory("一号滑梯");
    fx->Use(Kid("奇奇"));

    Slide* fy = f.GetSlideCategory("二号滑梯");
    fy->Use(Kid("天天"));

    Slide* fz = f.GetSlideCategory("三号滑梯");
    fz->Use(Kid("甜甜"));

    Slide* fl = f.GetSlideCategory("一号滑梯");
    fl->Use(Kid("嘟嘟"));

    Slide* fm = f.GetSlideCategory("二号滑梯");
    fm->Use(Kid("豆芽"));

    Slide* fn = f.GetSlideCategory("三号滑梯");
    fn->Use(Kid("年年"));

    cout << "得到滑滑梯总数:" << f.GetSlideCount() << endl;

    system("pause");
    return 0;
}

6.引用

C++设计模式 - 享元模式 - 知乎 (zhihu.com)

C++设计模式——享元模式 - 冰糖葫芦很乖 - 博客园 (cnblogs.com)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值