【设计模式】——享元模式

享元模式(Flyweight),运用共享技术有效地支持大量细粒度的对象。

 

#include <iostream>
#include <vector>
using namespace std;
//Flyweight类,它是所有具体享元类的超类或接口,通过这个接口,Flyweight可以接受并作用于外部状态
class Flyweight
{
public:
    virtual void Operator(int extrinsicstate)=0;
};
//ConcreteFlyweight是继承Flyweight超类或实现Flyweight接口,并为内部状态增加存储空间
class ConcreteFlyweight:public Flyweight
{
public:
    void Operator(int extrinsicstate)
    {
        cout << "具体Flyweight:" << extrinsicstate << endl;
    }
};
//UnsharedConcreteFlyweight是指那些不需要共享的Flyweight子类。因为Flyweight接口共享成为可能,但他并不强制共享
class UnsharedConcreteFlyweight:public Flyweight
{
public:
    void Operator(int extrinsicstate)
    {
        cout << "不共享的具体Flyweight:" << extrinsicstate << endl;
    }
};
//FlyweightFactory,是一个享元工厂,用来创建并管理Flyweight对象。它主要是用来确保合理的共享Flyweight,
//当用于请求一个Flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)
class FlyweightFactory
{
private:
    vector<Flyweight*> m_flyweights;
public:
    FlyweightFactory()
    {
        Flyweight *temp=new ConcreteFlyweight();
        m_flyweights.push_back(temp);
    }
    Flyweight *GetFlyweight(int key)
    {
        return m_flyweights.at(key);
    }
};
int main()
{
    int exetrinsicstate=22;
    FlyweightFactory *f=new FlyweightFactory();
    Flyweight *fx=f->GetFlyweight(0);
    fx->Operator(exetrinsicstate);
    return 0;
}

  在享元对象内部并且不会随环境改变而改变的共享部分,可以成为是享元对象的内部状态,而随环境改变而改变的、不可以共享的状态就是外部状态了。事实上,享元模式可以避免大量非常相似的开销。在程序设计中,有时需要生成大量细粒度的类实例来表示数据。如果能发现这些实例除了几个参数外基本上都是相同的,有时就能够受大幅度地减少需要实例化的类的数量。如果能把那些参数移到类实例的外面,在方法调用时将它们传递进来,就可以通过共享大幅度地减少单个实例的数目。也就是说,享元模式Flyweight执行时所需的状态是有内部的也可能有外部的,内部状态存储于ConcreteFlyweight对象之中,而外部对象则应该考虑由客户端对象存储或计算,当调用Flyweight对象的操作时,将该状态传递给它。

下面是关于网站分类的例子:

 

#include <iostream>
#include <map>
using namespace std;
//用户类,用于网站的客户帐号,是“网站”类的外部状态
class User
{
private:
    string m_name;
public:
    User(string name)
    {
        this->m_name=name;
    }
    string GetName()
    {
        return m_name;
    }
};
//网站抽象类
class WebSite
{
public:
    virtual void Use(User *user){}
};
//具体网站类
class ConcreteWebSite:public WebSite
{
private:
    string m_name;
public:
    ConcreteWebSite(string name)
    {
        this->m_name=name;
    }
    void Use(User *user)
    {
        cout << "网站分类:" << m_name << " 用户:" << user->GetName()<< endl;
    }
};
//网站工厂类
class WebSiteFactory
{
private:
    map<string,WebSite*> m_flyweights;
public:
    //获得网站分类
    WebSite *GetWebSiteCategory(string key)
    {
        if(m_flyweights.find(key)==m_flyweights.end())
            m_flyweights[key]=new ConcreteWebSite(key);
        return m_flyweights[key];
    }
};
int main()
{
    WebSiteFactory *f=new WebSiteFactory();
    WebSite *fx=f->GetWebSiteCategory("产品展示");
    fx->Use(new User("小菜"));
    WebSite *fy=f->GetWebSiteCategory("产品展示");
    fy->Use(new User("大鸟"));
    WebSite *f1=f->GetWebSiteCategory("博客");
    f1->Use(new User("老顽童"));
    WebSite *fm=f->GetWebSiteCategory("博客");
    fm->Use(new User("Awy"));
    return 0;
}

  如果一个应用程序使用了大量的对象,而大量的这些对象造成了很大的存储开销时,就应该考虑使用;还有就是对象的大多数状态可以是外部状态,如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式。因为用了享元模式,所以有了共享对象,实例总数就大大减少了,如果共享的对象越多,存储节约也就越多,节约量随着共享状态的增多而增大。

  在某些情况下,对象的数量可能会太多,从而导致了运行时的资源与性能损耗。那么我们如何去避免大量细粒度的对象,同时又不影响客户程序,是一个值得去思考的问题,享元模式,可以运用共享技术有效地支持大量细粒度的对象。不过,你也别高兴得太早,使用享元模式需要维护一个记录了系统已有的所有享元的列表,而这本身需要耗费资源,另外享元模式使得系统更加复杂。为了使对象可以共享,需要将一些状态外部化,使得程序的逻辑发扎花。因此,应当在有足够多的对象实例可供共享时才值得使用享元模式。

原文地址:https://www.cnblogs.com/awy-blog/p/3844027.html