设计模式-对象性能

对象性能

  • 前言
  • 1. Singleton
    • 1.1 模式介绍
    • 1.2 模式代码
    • 1.2.1 懒汉模式
    • 1.2.2 饿汉模式
  • 2. Flyweight
    • 2.1 模式介绍
    • 2.2 模式代码
    • 2.3 模式类图
    • 2.4 要点总结

前言

"对象性能”模式:面向对象很好地解决了“抽象”的问题,但是不可避免地要付出一定的代价。对于通常情况来讲,面向对象的成本大都可以忽略不计。但是某种情况下,面向对象所带来的成本必须谨慎处理。

典型模式:

  • Singleton 单例模式
  • Flyweight 享元模式

1. Singleton

1.1 模式介绍

单例模式为解决:

  1. 确保一个类只有一个实例。有些对象全局只应该存在一个,拥有多个在逻辑上会出问题。
  2. 为该实例提供全局访问点。有些对象有全局访问属性。

1.2 模式代码

1.2.1 懒汉模式

懒汉模式:即该对象只有在被第一次访问时才创建

class Singleton
{
public:
    static Singleton* GetInstance()
    {
        static Singleton  singleton;//此变量存在静态区,C++11自带两段检查锁机制来确保static变量实例化一次
        return &singleton;
    }
private:
    Singleton();
};
class Singleton
{
public:
    static Singleton* GetInstance()
    {
        if (p_singleton_ == nullptr)//第一次检查:实例化单例对象后,就不会再进入加锁逻辑
        {
            std::lock_guard<std::mutex> lock(mux_);
            if (p_singleton_ == nullptr)//第二次检查:可能两个线程同时通过第一次检查,一个线程获得锁时,可能另外一个线程已经实例化单体
            {
                p_singleton_ = new Singleton();
            }
        }
        return p_singleton_;
    }
private:
    Singleton();
    static Singleton * p_singleton_ ;
    static std::mutex mux_;
};

1.2.2 饿汉模式

饿汉模式:即该对象在程序初始阶段进行创建

class Singleton{
public:
    static Singleton* GetInstance()
    {
        return &_inst;
    }
private:
    Singleton()
    {}
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton& ) = delete;
    static Singleton _inst;
};

Singleton Singleton::_inst;

2. Flyweight

2.1 模式介绍

动机:在软件系统采用纯粹对象方案的问题在于大量细粒度的对象会很块充斥在系统中,从而带来很高的运行时代价—主要指内存需求方面的代价。

如何在避免大量细粒度对象问题的同时,让外部客户程序仍然能透明地适用面向对象的方式来进行操作?

运用共享技术有效地支持大量细粒度的对象。

——《设计模式》GOF

为了在忙碌的工作后放松身心,您决定制作一款简单的视频游戏:玩家将在地图上移动并互相射击。您选择实现逼真的粒子系统,并使其成为游戏的一大特色。大量的子弹、导弹和爆炸产生的弹片应该会飞遍整个地图,为玩家带来惊心动魄的体验。

完成后,您推送了最后一次提交,构建了游戏并将其发送给您的朋友进行测试。尽管游戏在您的机器上运行完美,但您的朋友却无法玩很长时间。在他的计算机上,游戏在玩了几分钟后就崩溃了。在花了几个小时研究调试日志后,您发现游戏崩溃是因为 RAM 不足。原来,您朋友的装备比您自己的电脑弱得多,这就是为什么问题如此迅速地出现在他的机器上。

实际问题与粒子系统有关。每个粒子(例如子弹、导弹或弹片)都由包含大量数据的单独对象表示。在某个时候,当玩家屏幕上的屠杀达到高潮时,新创建的粒子不再适合剩余的 RAM,因此程序崩溃了。

仔细观察代码后发现,非常多的粒子具有相同的颜色,而颜色占用的内存比较多,没必要为那么多相同的颜色都开辟空间

2.2 模式代码

通常一篇文章所用到的字体最多也就几种,而一篇文章的字数却可以有很多,如果每个字都包含字体属性,会造成大量的空间浪费,于是可以将字体提出来,单独进行映射。

#include 
#include 
using namespace std;
class Font {
private:

    //unique object key
    string key;
    
    //object state
    //....
    
public:
    Font(const string& key){
        //...
    }
};

class FontFactory{
private:
    map<string,Font* > fontPool;
    
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(){
        //...
    }
};

2.3 模式类图

设计模式-对象性能_第1张图片

2.4 要点总结

  • 面向对象很好地解决了抽象性的问题,但是作为一个运行在机器中的程序实体,我们需要考虑对象的代价问题。Flyweight主要解决面向对象的代价问题,一般不触及面向对象的抽象性问题。
  • Flyweight采用对象共享的做法来降低系统中对象的个数,从而降低细粒度对象给系统带来的内存压力。在具体实现方面,要注意对象状态的处理。
  • 对象的数量太大从而导致对象内存开销加大——什么样的数量才算大?这需要我们仔细的根据具体应用情况进行评估,而不能凭空臆断。

你可能感兴趣的:(设计模式,设计模式,单例模式,享元模式,C++)