静态保护资源通过继承共享

时间:2012-06-10 01:33:40

标签: c++ design-patterns inheritance

为了尝试替换单例模式和一般的“资源管理器”,我提出了一个解决方案。使资源保持静态和受保护。该资源由继承类的所有子级共享。它有效,但我不确定这是否是一个好的方法。 这里有一些代码来表达我正在做的事情(这里的资源是sf :: Texture):

class Foo {
public:
    Foo() {
        if(m_texture == nullptr) {
            //Création et chargement de la texture
            m_texture = std::unique_ptr<sf::Texture>(new sf::Texture());
            m_texture->loadFromFile("...");
        }

    }

    void draw(sf::RenderWindow& window) = 0;

protected:
    static std::unique_ptr<sf::Texture> m_texture = nullptr;

};

class Bar : public Foo {
public:
    Bar()
        : m_sprite(*m_texture) {}

    void draw(sf::RenderWindow& window) {
        window.draw(m_sprite); 
    }

private:
    sf::Sprite m_sprite;
};

这样我的资源就可以通过所有孩子共享,并且只会被初始化一次。 这是一个很好的解决方案来替换我将通过引用随处携带的单例或资源管理器。 谢谢!

2 个答案:

答案 0 :(得分:1)

从根本上说你要做的事情是正确的,一个静态成员将在所有继承的类中共享(即完全相同),这样你只需要一个可以节省大量内存的实例但是继承人几个问题...我假设你正在使用g ++。

你不能在类声明中初始化非const成员,所以这个 static std::unique_ptr<sf::Texture> m_texture = nullptr;
会产生这个:
错误:ISO C ++禁止非常规静态成员的类内初始化
你必须在你的类的源文件中初始化它,但在类之外。 std::unique_ptr<sf::Texture> Foo::m_texture = nullptr;

其次不是保存直接访问成员字段,总是使用setter和getter,即使在类函数中也是如此,这使得代码更易于维护。因此,您可以使用名为getTexture

的静态函数
static std::unique_ptr<sf::Texture> getTexture() {
    if(m_texture == nullptr) {
        //Création et chargement de la texture
        m_texture = std::unique_ptr<sf::Texture>(new sf::Texture());
        m_texture->loadFromFile("...");
    }
    return m_texture;
}

虽然if语句和函数调用确实添加了开销,但这更加可维护和更安全,并且它在真正需要的最后一刻加载纹理。

回到你的问题,Singleton设计模式非常简单,主要用于节省内存,因为只创建了一个对象实例:)资源管理器是一个完全不同的野兽,他们的目标是集中所有的操作需要加载和管理资源,将初始化资源管理器的单个实例组合在一起,然后通过静态成员字段访问它,让所有对象都对资源进行请求,这可能是好的还是坏的,这取决于你正在努力实现。

软件设计很难。我能给出的最好的建议是,在设计一个系统时问问自己,“我需要编写多少行代码才能引入另一个类似的组件”,你的目标应该是尽可能地减少这个,即尽可能多地重用你可能已经创造了什么。

最好的程序员是最懒的:)而且我不是指复制/粘贴,应该被禁止。

答案 1 :(得分:0)

设计看起来很可疑。我没有看到在更广泛使用的Singleton模式(使用函数本地静态实例)上使用它的任何优点。您可能最好在定义时使用默认m_texture初始化Texture对象(而不是在Foo的ctor中):

static std::unique_ptr<sf::Texture> m_texture( new sf::Texture() );

数据成员非常适合派生类。基类通常用于定义接口。

我建议您将资源管理器类(Foo)分开,而不是继承它,调用适当的成员函数来访问Texture对象。