簡體   English   中英

模板和依賴注入

[英]Templates and dependency injection

我有一個類模板ResourceManager ,旨在用於如下所示的內容:

ResourceManager<Image>* rm =
    ResourceManager<Image>::Instance();

Image* img = rm->acquire("picture.jpg");
rm->release(img);

我想使用依賴注入(將ResourceManager作為參數傳遞給應該使用它的函數,而不是使其全局使用),但是鑒於它是模板,所以我不知道該怎么做。 你有什么建議嗎?

我的游戲才剛剛開始開發,我已經擁有四種資源類型( ImageFontAnimationSound ),因此不能為每種類型的資源制作具有獲取功能的單個ResourceManager (即不是模板) 。


編輯:一些澄清。

我要尋找的不是對一種類型的ResourceManager進行依賴注入,而是一次對所有它們進行依賴注入。

我的GameState對象在初始化/打開時需要加載資源; 他們通過ResourceManagers這樣做。 但是, GameStates可能需要加載任意數量的資源類型:動畫,字體,圖像,聲音等-每種ResourceManager都有很多功能參數! 你建議我做什么?

好吧,如果函數需要一種特定類型的資源(可能會用得最多),只需將特定的模板實例定義為參數:

function(ResourceManager<Image> *rm, ...);

如果該功能需要任何種類的資源,則可以

  1. 成為模板本身,例如:

     template <typename T> function(ResourceManager<T> *rm, ...); 

    可能需要引用從資源管理器獲得的資源,因此無論如何它都需要在更多位置使用template參數。

  2. 使用多態基類。 那意味着您必須定義類似

     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抽象基類,因此您可以引用任何類型的資源。

選擇是在具有模板功能的更快但非常大的代碼(該函數將針對每個專業分別編譯)之間的權衡問題,或者是使用虛擬方法的較慢但較小的代碼(對虛擬方法的調用較慢,但是沒有代碼重復) )。 模板變體的編譯速度也較慢,因為大多數編譯器將為使用它的每個目標文件生成代碼,而不是在鏈接時合並相同的副本。

使用構造函數注入的示例:

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 ...
}

請注意,我省略了所有資源管理。 在適用的地方使用智能指針等。

第一。 請記住,使用模板時,必須在編譯時解決所有問題。

然后,代碼中的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)
  {}

  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();
}

注釋者注意:我很清楚資源泄漏,但這不是重點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM