模板和依赖注入

我有一个类模板
ResourceManager
,它打算使用这样的东西:
ResourceManager<Image>* rm =
    ResourceManager<Image>::Instance();

Image* img = rm->acquire("picture.jpg");
rm->release(img);
我想使用依赖注入(将
ResourceManager
作为参数传递给应该使用它而不是全局使用的函数),但是鉴于它是一个模板,我不知道如何做到这一点。你有什么建议吗? 我的游戏只是在开发的开始,我已经有四种资源类型(
Image
Font
Animation
Sound
),因此为每种类型的资源制作一个带有获取功能的单个
ResourceManager
(即非模板)不是一种选择。 编辑:一些澄清。 我正在寻找的不是如何为一种类型的ResourceManager进行依赖注入,而是一次性对所有这些进行依赖注入。 我的
GameState
对象在初始化/打开时需要加载资源;他们通过
ResourceManagers
这样做。但是,
GameStates
可能需要加载任意数量的资源:动画,字体,图像,声音等等&mdash;这是每种
ResourceManager
的很多功能参数!你有什么建议我这样做?     
已邀请:
好吧,如果函数需要特定类型的资源(可能是大多数),只需将特定模板实例定义为参数:
function(ResourceManager<Image> *rm, ...);
如果函数需要任何类型的资源,那么它也可以 是一个模板本身,如:
template <typename T>
function(ResourceManager<T> *rm, ...);
它可能需要引用从资源管理器获得的资源,因此无论如何它将需要更多地方的模板参数。 使用多态基类。这意味着你必须定义类似的东西
class ResourceManagerBase { /* methods you need to call via the base class */ };
template <typename T>
class ResourceManager : ResourceManagerBase { ... };

function(ResourceManagerBase *rm, ...)
该函数可以调用基类中定义的任何方法。如果方法在内部依赖于资源类型,则它们将在基础中声明为抽象虚拟(
virtual returnType method(...) = 0
)并在模板类本身中定义。您还可以使用
dynamic_cast
来检查您所拥有的
ResourceManager
的具体实例。 注意,如果函数需要引用资源,您同样需要一个所有资源的
ResourceBase
抽象基类,因此您可以引用任何类型的资源。 选择是在具有模板功能的较快但非常大的代码之间进行权衡(该函数将针对每个特化分别编译)或者使用虚拟方法较慢但较小的代码(调用虚方法较慢,但没有代码重复) )。此外,模板变体编译速度较慢,因为大多数编译器将为使用它的每个目标文件生成代码,而不是在链接时合并相同的副本。     
第一。请记住,在使用模板时,必须在编译时解决所有问题。 然后代码中的ResourceManager似乎是单例。因此,粗略地讲,与全局变量没有区别。 当你可以直接调用单例时,我认为这是无用的传递rm作为函数的参数。 我希望,这可以解决你的问题。     
使用构造函数注入的示例:
template<typename T>
struct ResourceManager
{
  virtual T* acquire(std::string const& resourceName)
  { return ...; }
  ... etc ...
};

class ImageUser
{
  ResourceManager<Image>* rm_;

  public:
  explicit ImageUser(ResourceManager<Image>* rm)
    : rm_(rm)
  {}

  ImageUser()
    : rm_(ResourceManager<Image>::Instance())
  {}

  void UseImage()
  {
    Image* img = rm_->acquire("picture.jpg");
    rm_->release(img);
  }
};


struct ImageResourceManagerFake : ResourceManager<Image>
{
  virtual Image* acquire(std::string const& resourceName) // override
  { return <whatever-you-want>; }
  ... etc ...
};

void test_imageuser()
{
  ImageResourceManagerFake* rm = new ImageResourceManagerFake;
  ImageUser iu(rm);
  ... test away ...
}
请注意,我遗漏了所有资源管理;在适用的地方使用智能指针等。     
即使在你编辑之后,我发现有点难以理解你所看到的是什么而没有看到整个画面,但我将在一个基本的例子中再次尝试:
template<typename T>
struct ResourceManager
{
  virtual T* acquire(std::string const& resourceName)
  { return ...; }
  // ... etc ...
};

class ImageUser
{
  ResourceManager<Image>* rm_;

  public:
  explicit ImageUser(ResourceManager<Image>* rm)
    : rm_(rm)
  {}

  void UseImage()
  {
    Image* img = rm_->acquire("picture.jpg");
    rm_->release(img);
  }
};

template<typename T>
struct ResourceManagerFake : ResourceManager<T>
{
  T* acquireRetVal;
  virtual T* acquire(std::string const& resourceName)
  { return acquireRetVal; }
  // ... etc ...
};

void test_imageuser()
{
  ResourceManagerFake<Image>* rm = new ResourceManagerFake<Image>;
  rm->acquireRetVal = new Image;
  ImageUser iu(rm);

  iu.UseImage();
}
评论者注意:我很清楚资源泄漏,但这不是重点。     

要回复问题请先登录注册