2011-01-23 75 views
4

我已經創建了一個我打算在遊戲中使用的簡單GUI引擎。 我遇到的問題是理解如何實例化一個將在多個堆棧框架中訪問而不是靜態的類(人們已經很清楚靜態變量只是邪惡的)。什麼是這些靜態變量的可能替代方案?

我有以下代碼示例:

class MyGame 
{ 
    class InputEngine 
    { 
     internal void DoInput() 
     { 
      if (Keys["F1"].IsPressed) 
      { 
       // Create a window using the gui engine 
      } 
     } 
    } 
    class GuiEngine 
    { 
     internal void Update() { } 
     internal void Draw() { } 
    } 
    private GuiEngine engine; 
    private InputEngine input; 

    internal MyGame() 
    { 
     this.input = new InputEngine(); 
     this.engine = new GuiEngine(); 
    } 

    internal void Update() 
    { 
     this.engine.Update(); 
     this.input.DoInput(); 
    } 
    internal void Draw() 
    { 
     this.engine.Draw(); 
    } 
} 

我怎樣才能訪問GUI引擎實例不僅從輸入例子,但是從幾十其他地方不使其靜態的。 (我真的不想把它作爲參數傳遞)。

+0

謝謝大家對你非常有用的答案!你給了我很多想法,那就是我會做的。喝杯咖啡,看看我能如何實施這些建議。 – Tony 2011-01-23 09:41:51

回答

1

你只得到了三個實傳球選擇 -

  • 參數(cctor,方法等)
  • 代表/瓶蓋/λ

技術如反轉的控制容器在創建,管理生命週期和發現實例方面也能起到幫助作用。添加依賴注入,整個生命週期可以自動化,並且最小的歸屬/編碼。

在這三種技術中,靜力學和參數化通過了軟件維護「測試」,從明顯性和簡單性的角度來看最好。IoC是相當可讀的。然而,DI代碼庫往往感覺更像黑魔法,對於生命週期,位置和綁定具有隱含的行爲。

委託,關閉等可以很好地工作,創建時保留上下文,但調試可能有點噩夢,並且經常維護/讀取閉包代碼感覺混亂,因爲它很少在寫入它的地方執行。

靜如你所指出的可能是最粗糙的,是很難嘲笑,更換等。

0

Game的實例傳遞給其他類的構造函數,並將其保存在局部變量中。這樣,您幾乎可以從任何地方訪問Game及其所有成員,但仍可以有多個遊戲實例。

您可以通過使用依賴注入來自動執行該操作。

在某些情況下,線程靜態變量是一種選擇,但我不認爲你是其中之一。

2

您的問題的解決方案可能會重新設計。也有一些是錯誤的,當你需要

訪問GUI引擎實例不僅從輸入例子,但是從幾十其他地方

這表明大量的依賴關係,可能是錯誤的。

0

您可以使用IoC框架並使用依賴注入將輸入引擎放在需要的位置。另外,您可以使用「服務定位器」模式。

1

也許你可以在你的遊戲引擎類型中實現singleton pattern? 如果你沒有創建超過1個對象實例,我認爲這是理想的選擇。

否則,您可以嘗試使用IoC解決方案,如Mincrosoft的Unity

+0

簡單地使用靜態字段,他試圖避免這種情況。 – CodesInChaos 2011-01-23 09:18:13

0

該技術被稱爲依賴注入。實際上,您正在將「靜態變量」「注入」實例。就實例而言,它是一個普通的實例變量。您只需將您的gui實例傳遞給構造函數。

0

你可以把它作爲一個構造函數的參數,而不是一個方法的參數,如:

public class InputEngine 
{ 
    public InputEngine(IGuiEngine guiEngine) 
    { 
     // set private member to store guiEngine 
    } 
} 

注意我還將GuiEngine更改爲一個接口 - 這樣,您可以使用依賴注入容器(例如StructureMap)根據需要自動將GUI引擎傳遞給您的實例。也幫助測試。

或者,您可以使用DI容器或工廠類來提供GUI引擎的單例實例。

0

現在靜態的第一件事是邪惡的是恕我直言,不是靜態函數,單身類本身是邪惡的。但是,如果您想爲使用靜態上下文的類創建一些自動化測試,那幾乎是不可能的。

因此,如果您想完全忽視創建自動化測試的任何希望,那麼請繼續,使靜態數據成爲靜態類。

如果你想保持這個選項打開,那麼我建議你看看像IOC容器(structuremap是我最喜歡的東西)。您可以有一個(ahem)靜態IOC容器,您可以使用它來創建依賴關係的實例。依賴關係將採用例如GuiEngine作爲構造函數的參數。並且您的IO​​C容器將確保所有依賴項都接收相同的實例,假設您已正確配置它。正如Tim指出的那樣,爲你的引擎類提取一個接口將是一個不錯的主意,因爲它可以讓你爲所述測試創建替代實現,例如,模擬,存根,間諜,假對象等。

2

依賴注入是你的朋友。如前所述,通過構造函數暴露依賴(這似乎是典型的方式),或者你可以通過屬性注入來實現。無論如何,當你在應用程序啓動時註冊你的依賴項時,你可以告訴容器使它成爲一個單身,所以當你要求參考時,你會得到與靜態參考相同的效果。

對於Ninject,語法是:

var kernel = new Ninject.StandardKernel(settings); 
kernel.Bind<ISomeInterface>().To<MyConcreteObject>().InSingletonScope(); 

對於Unity,語法是:

UnityContainer container = new UnityContainer(); 
container.RegisterType<ISomeInterface, MyConcreteObject>(new ContainerControlledLifetimeManager()); 

所以,你的類可以是這樣的:

public class MyThing 
{ 
    ISomeInterface _mySingletonObject; 

    public MyThing(ISomeInterface mySingletonObject) 
    { 
     _mySingletonObject = mySingletonObject; 
    } 
} 

這個類總是獲得注入對象的相同實例,前提是使用容器來解析該類的實例秒。

再次,Ninject:

var singletopnObject = kernel.Get<ISomeInterface>(); 

和統一(我認爲從內存)

var singletopnObject = container.Resolve<ISomeInterface>(); 

和所有其他IoC容器提供以不同的方式相同的功能。

P.S.靜力學不是邪惡的。正確使用時,它們很快且非常有用。