结构型模式之 享元模式

Posted wsmsyiddbzc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了结构型模式之 享元模式相关的知识,希望对你有一定的参考价值。

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

面向对象技术可以很好地解决一些灵活性或可扩展性问题,但在很多情况下需要在系统中增加类和对象的个数。当对象数量太多时,将导致运行代价过高,带来性能下降等问题。

  • 享元模式正是为解决这一类问题而诞生的。享元模式通过共享技术实现相同或相似对象的重用。
  • 在享元模式中可以共享的相同内容称为内部状态(IntrinsicState),而那些需要外部环境来设置的不能共享的内容称为外部状态(Extrinsic State),由于区分了内部状态和外部状态,因此可以通过设置不同的外部状态使得相同的对象可以具有一些不同的特征,而相同的内部状态是可以共享的。
  • 在享元模式中通常会出现工厂模式,需要创建一个享元工厂来负责维护一个享元池(Flyweight Pool)用于存储具有相同内部状态的享元对象。
  • 在享元模式中共享的是享元对象的内部状态,外部状态需要通过环境来设置。在实际使用中,能够共享的内部状态是有限的,因此享元对象一般都设计为较小的对象,它所包含的内部状态较少,这种对象也称为细粒度对象。享元模式的目的就是使用共享技术来实现大量细粒度对象的复用。

主要解决:在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。

何时使用: 1、系统中有大量对象。 2、这些对象消耗大量内存。 3、这些对象的状态大部分可以外部化。 4、这些对象可以按照内蕴状态分为很多组,当把外蕴对象从对象中剔除出来时,每一组对象都可以用一个对象来代替。 5、系统不依赖于这些对象身份,这些对象是不可分辨的。

如何解决:用唯一标识码判断,如果在内存中有,则返回这个唯一标识码所标识的对象。

关键代码:用 HashMap 存储这些对象。

优点:大大减少对象的创建,降低系统的内存,使效率提高。

缺点:提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱。

使用场景: 1、系统有大量相似对象。 2、需要缓冲池的场景。

注意事项: 1、注意划分外部状态和内部状态,否则可能会引起线程安全问题。 2、这些类必须有一个工厂对象加以控制。

实现

我们将创建一个 Shape 接口和实现了 Shape 接口的实体类 Circle。下一步是定义工厂类 ShapeFactory

ShapeFactory 有一个 Circle 的 HashMap,其中键名为 Circle 对象的颜色。无论何时接收到请求,都会创建一个特定颜色的圆。ShapeFactory 检查它的 HashMap 中的 circle 对象,如果找到 Circle 对象,则返回该对象,否则将创建一个存储在 hashmap 中以备后续使用的新对象,并把该对象返回到客户端。

FlyWeightPatternDemo,我们的演示类使用 ShapeFactory 来获取 Shape 对象。它将向 ShapeFactory 传递信息(red / green / blue/ black / white),以便获取它所需对象的颜色。

#include<iostream>
#include<memory>
#include<list>
#include<map>
#include <utility>
#include<time.h>
#include<string>
using namespace std;

//步骤一 创建一个接口
class Shape 
{
public:
    virtual void draw() {}
};
//步骤二 创建实现接口的实体类

class Circle : public Shape
{
private:
    std::string color;
    int x;
    int y;
    int radius;
public:
    Circle() { color = "red"; x = y = radius = 0; }
    Circle(string Color) { color = Color; }
    void SetX(int X) { x = X; cout << "x = " << x << endl; }
    void SetY(int Y) { y = Y; }
    void SetRadius(int Radius) { radius = Radius; }
    void draw()
    {
        std::cout << "Circle::draw() color = " << color << "  x = " << x << "  y = " << y << "   radius = " << radius << std::endl;
    }
};

//步骤 3    创建一个工厂,生成基于给定信息的实体类的对象
class ShapeFactory
{
private:
    static std::map<string, Shape*> circleMap;
public:
    static Shape* GetCircle(string color)
    {
        if (color.empty())
            return NULL;
        std::map<string, Shape*>::iterator ite = circleMap.find(color);
        if (ite != circleMap.end())
            return(ite->second);
        else 
        {
            Shape* shapetmp = new Circle;
            pair<string, Shape*> p1;
            p1 = make_pair(color, shapetmp);
            circleMap.insert(p1);
            cout << "Creating circle of color : " << color << endl;
            std::map<string, Shape*>::iterator ite2 = circleMap.find(color);
            if (ite2 != circleMap.end())
                return(ite2->second);
            return NULL;
        }
    }
    ShapeFactory() {
    }
};
map<string, Shape*>ShapeFactory::circleMap;  //静态成员变量一定要初始化,否则出现链接问题


int main() 
{
    
    string colors[] =
    { "Red", "Green", "Blue", "White", "Black" };
    srand((int)time(0));
    string s1 = colors[rand() % colors->size()];
    cout << s1 << endl;
    for (int i = 0; i < 20; ++i) {
        
        Circle* circle = (Circle*)ShapeFactory::GetCircle(s1);
        circle->SetX(rand() % 100);
        circle->SetY(rand() % 100);
        circle->SetRadius(rand() % 100);
        circle->draw();
    }
    return 0;
}
//未考虑new的内存释放问题,说明一下

 

以上是关于结构型模式之 享元模式的主要内容,如果未能解决你的问题,请参考以下文章

15结构型模式之享元模式

JAVA SCRIPT设计模式--结构型--设计模式之FlyWeight享元模式(11)

学习设计模式之享元模式

结构型模式之享元模式

结构型模式之 享元模式

结构型模式之享元