创建一个子类的多个实例,只有一个超类的一个实例

问题描述 投票:1回答:2

我正在尝试实现Flyweight模式,但我不太确定继承如何工作,因此我不确定此模式如何工作。

假设我有一个超类,其中包含所有“大量”信息-纹理等内在信息(永不改变的信息)。

class Block{
public: //for the sake of the example
Texture tex; 
etc.
};

而且我的light类的数据会发生变化:

class Block_light : public Block {
public:
int posX, posY, posZ;
int color;
etc.
};

因此,如果我主要创建n Block_light,我还将创建n Block还是将它们全部绑定到一个实例?

 int main(){
 std::vector<Block_light> blocks(n);
 return 0;
 };

我创建n Block_light和1 Block还是n Block_light和n Block吗?如果是后者,我该如何做,使其仅使用一个实例?

c++ inheritance design-patterns subclass superclass
2个回答
0
投票

您实现的不是轻量级模式。没有Block_light之类的东西,而是Block是由Block1之类的东西提供的实现的纯接口,该实现类似于您的Block定义。

例如:

#include <string>
#include <unordered_map>
#include <memory>

class BlockState {
public:
    int posX, posY, posZ;
    int color;
};

struct Texture {
    Texture(const std::string &);
    char data[8196];
};

class Block {
public:
    Block(std::string) {};
    virtual void render(const BlockState &state) const = 0;
};

class Block1 final : public Block {
public:
    Block1(std::string name) : Block(name), tex(name) {};
    void render(const BlockState &state) const override;
private:
    const Texture tex;
};

class BlockFactory final {
public:
    std::shared_ptr<const Block> getBlock(const std::string &key) {
        auto it = dict.find(key);
        if(it != dict.end()) return it->second;
        auto it2 = dict.try_emplace(key, std::make_shared<Block1>(key));
        return it2.first->second;
    }
private:
    std::unordered_map<std::string, std::shared_ptr<const Block>> dict;
};

void render () {
    static BlockFactory factory;
    BlockState a, b;
    factory.getBlock("brick")->render(a);
    factory.getBlock("brick")->render(b);
}

BlockFactory正在为您管理Block的实例,由不可见的Block1实现实现。使用其他工厂进行测试等,您可以根据需要切换下面的实现以进行测试。

您的“每个实例”状态不是从Block继承,而是保持独立和按值分配,因为Block实例由BlockFactory拥有,并且仅通过引用/指针传递。


0
投票

C ++对象模型确保子类(即derived类)的每个实例contains也是其所有超类(即base类)的自己的实例。

在您的情况下,这意味着每个Block_light对象将具有所有Block_light属性,以及具有所有Block属性的Block子对象。换句话说,Block_light一点也不轻。

如果要共享一个公共状态:

  • 您可以use composition instead of inheritanceBlock_light不会继承Block,而是引用共享的Block对象。
  • 但是,如果您仍然需要能够互换使用BlockBlock_light,则可以使它们都从一个公共接口(即仅具有虚拟功能且没有状态的clss)继承IBlock
  • 您也可以使用flyweight pattern,其中状态的一部分(共享或不共享)被“外部化”为extrinsinc状态。此模式的特殊之处在于,调用方将对外部状态的引用提供给类函数,因此,举重对象无需存储指向该状态的指针。

第一个选项如下:

class Block {...}; 
class Block_light {       // no inheritance 
    shared_ptr<Block> b;  // but (private) composition   
    ...
};  

第二种选择是:

class IBlock {  // no member variables
public:
    virtual Texture get_texture()=0;
    virtual ~IBlock(){}; 
};  

class Block : public IBlock {  // sharable state
    Texture tex; 
public: 
    Texture get_texture() override { return tex; }
};    

class Block_light : public IBlock {
    shared_ptr<IBlock> b;  // or IBlock or Block depending on the needs.  
public:
    Block_light (shared_ptr<IBlock>i) : b(i) {}
    Texture get_texture() override { return b->get_texture(); }
};  

int main() { // just a perfectible quick example
    auto myb=make_shared<Block>();
    Block_light b1(myb);
    b1.get_texture();
}

最后一个将这样使用:

int main() { // just a perfectible quick example
    Block myb;     // shared part; 
    Block_light bl;
    bl.get_texture(myb);
}

我将不介绍flyweight实现的详细信息,但是您有an example here。但是,在选择此模式之前,请三思而后行,因为提供共享上下文可能具有挑战性并且容易出错。

© www.soinside.com 2019 - 2024. All rights reserved.