zoukankan      html  css  js  c++  java
  • 设计模式---对象性能模式之享元模式(Flyweight)

    一:概念

    通过与其他类似对象共享数据来减少内存占用
    如果一个应用程序使用了太多的对象, 就会造成很大的存储开销。 
    特别是对于大量轻量级 (细粒度)的对象,比如在文档编辑器的设计过程中,我们如果为每个字母创建一个对象的话,系统可能会因为大量的对象而造成存储开销的浪费。
    例如一个字母“a”在文档中出现了100000 次,而实际上我们可以让这一万个字母“a”共享一个对象,当然因为在不同的位置可能字母“a”有不同的显示效果(例如字体和大小等设置不同) ,
    在这种情况我们可以为将对象的状态分为“外部状态”和“内部状态” ,
    将可以被共享(不会变化)的状态作为内部状态存储在对象中,而外部对象(例如上面提到的字体、大小等)我们可以在适当的时候将外部对象最为参数传递给对象(例如在显示的时候,将字体、大小等信息传递给对象) 。 Flyweight 模式可以解决上面的问题,

    二:动机

    在软件系统中采用纯粹对象方案的问题 在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行时代价——主要指内存需求方面的代价。
    如何在避免大量·细粒度对象问题的同事,让外部客户程序仍然能够透明地使用面向对象的方式来进行操作?

    三:模式定义

    运用共享技术有效地支持大量的细粒度对象                                        
    
                                                   ——《设计模式》GoF

    四:代码讲解

    class Font {  //用来描述字体
    private:
    
        //unique object key
        string key;
        
        //object state
        //....
        
    public:
        Font(const string& key){  //利用这个key来创建对象
            //...
        }
    };
    class FontFactory{
    private:
        map<string,Font* > fontPool;  //map映射key--对象指针
        
    public:
        Font* GetFont(const string& key){
    
            map<string,Font*>::iterator item=fontPool.find(key);
            
            if(item!=footPool.end()){
                return fontPool[key];  //若存在则共享
            }
            else{
                Font* font = new Font(key);  //不存在则添加
                fontPool[key]= font;
                return font;
            }
    
        }
        
        void clear(){
            //...
        }
    };
    实现是多种的,但是总体思想是一样的

    五:类图(结构)

    六:要点总结

    (一)面向对象很好的解决了抽相性的问题,但是作为一个运行在机器中的程序实体,我们需要考虑对象的代价问题。Flyweight主要解决面向的代价问题,一般不触及面向对象的抽象性问题。

    (二)Flyweight采用对象共享的做法来降低系统中的对象的个数,从而降低细粒度对象给系统带来的内存压力。在具体实现方面,要注意对像状态的处理。

    注意:上面的Font对象一旦创建出来,状态就无法更改了,是只读的。共享最好就是只读的,不允许随便修改

    (三)对象的数量太大,从而导致对像内存开销加大——什么样的数量才算大?这需要我们仔细根据具体应用情况进行评估,而不能凭空臆断。 

    字段,字节对齐,虚函数表指针(有10个虚函数,也只有一个虚函数表指针),总共加起来假设有10字段40字节
    1024个对象:40*1024=40kb
    102400个对象:40:1024*100=4000kb~4M
    不能臆想,需要去评估,用于处理对象过多时使用享元模式

    七:案例实现:享元模式存放教师信息

    (一)教师类实现

    #include <iostream>
    #include <stdlib.h>
    #include "map"
    #include "string"
    
    using namespace std;
    
    class Person
    {
    protected:
        string name;
        int age;
        int sex;
    public:
        Person(string name, int age, int sex)
        {
            this->name = name;
            this->age = age;
            this->sex = sex;
        }
    
        string getName()
        {
            return name;
        }
    
        int getAge()
        {
            return age;
        }
    
        int getSex()
        {
            return sex;
        }
    };
    
    class Teacher :public Person
    {
    private:
        string id;
    public:
        Teacher(string id, string name, int age, int sex) :Person(name, age, sex)
        {
            this->id = id;
        }
    
        string getId()
        {
            return id;
        }
    
        void printInfo()
        {
            cout << "id:" << id << "	name:" << name << "	age" << age << "	sex:" << sex << endl;
        }
    };

    (二)享元模式工厂

    class TeacherFactory
    {
    private:
        map<string, Teacher*> TeacherPool;
    public:
        Teacher* getTeacher(const string& key)
        {
            string name;
            int age;
            int sex;
            Teacher* tmp;
    
            map<string, Teacher*>::iterator iter = TeacherPool.find(key);
            if (iter == TeacherPool.end())
            {
    
                cout << "id为:" << key << "teacher is not exists,you need to add info for it" << endl;
                cout << "please input teacher`s name:";
                cin >> name;
                cout << "please input teacher`s age:";
                cin >> age;
                cout << "please input teacher`s sex:";
                cin >> sex;
    
                tmp = new Teacher(key, name, age, sex);
                TeacherPool.insert(pair<string, Teacher*>(key, tmp));
            }
            else
                tmp = iter->second;
            return tmp;
        }
    };

    (三)测试

    void main()
    {
        TeacherFactory* teacherfactory = new TeacherFactory();
        Teacher* t1 = teacherfactory->getTeacher("001");
        t1->printInfo();
    
        Teacher* t2 = teacherfactory->getTeacher("002");
        t2->printInfo();
    
        Teacher* t3 = teacherfactory->getTeacher("001");
        t3->printInfo();
    
        system("pause");
        return;
    }

  • 相关阅读:
    Spring学习记录-源码构建
    Spring学习记录
    java相关技术提纲
    Seata 分布式事务框架
    SourceTree学习记录
    其他源码管理工具
    分布式事务
    Score (模拟题)
    大整数排序
    字符串的查找删除 时间限制:1 Seconds 内存限制:32 Mbyte
  • 原文地址:https://www.cnblogs.com/ssyfj/p/9540354.html
Copyright © 2011-2022 走看看