2015-12-21 64 views
0

我有一個帶有靜態變量的基類。我想創建派生子類,它將自動擁有自己的未共享靜態變量。理想情況下,應該是這樣的:自動爲每個派生類創建一個靜態變量的副本

class Parent 
{ 
    Texture2D picture; 
    static Texture2D pictureOrigin; 

    Parent() 
    { 
     picture = pictureOrigin; 
     /*Loading the static origin to an instance variable 
     because I might want to have more pictureOrigins 
     and alternate them or perhaps change the picture 
     of the instance based on a certain event, etc.*/    
    } 
} 

class Subclass1 : Parent //Edit: forgot to write the inheritance in this example 
{ 
    Subclass1() : base() 
    { } 
} 

class Subclass2 : Parent 
{ 
    Subclass2() : base() 
    { } 
} 

void main() 
{ 
    Parent.pictureOrigin = Load("pictureForParent"); 
    Subclass1.pictureOrigin = Load("pictureForSubclass1"); 
    Subclass2.pictureOrigin = Load("pictureForSubclass2"); 
    //Then creating instances of the classes and drawing them, etc. 
} 

但發生的事情是,他們都獲得了最後的加載圖像(pictureForSubclass2),因爲靜態變量pictureOrigin在它們之間共享。

最快鎖定被手動添加新的靜態變量pictureOrigin到每個子類和隱藏的基類的pictureOrigin變量:

class Subclass1 : Parent 
{ 
    new static Texture2D pictureOrigin; 

    Subclass1() : base() 
    { 
     picture = pictureOrigin; 
    } 
} 

此外,在創建抽象方法或類似,以確保新的靜態變量的創建在子類中。但它似乎太麻煩,不太優雅。有沒有更好的方法來做到這一點?

+0

靜態看起來像一個壞主意,它爲什麼必須是靜態的任何理由?您可以將圖像資源加載到某個圖像存儲區,然後將所需圖像提供給每個實例? –

+0

在您的代碼中,Subclass1和Subclass2不是從Parent繼承的。 –

+0

您可以使'Parent'通用,就像'父Parent 其中T:Parent ',然後繼承指定子類的類型:'class Subclass1:Parent '。然後你會利用這樣一個事實,即每個「」類型的獨特組合將獲得他們自己的所有靜態字段的副本。話雖如此,我會盡量擺脫'static'關鍵字,並找到一種不同的方式來做到這一點。 –

回答

1

你的問題聞起來像一個糟糕的設計。在我看來,靜態變量通常是不好的實踐,適當的面向對象設計可以消除永遠使用靜態成員的需要。

嘗試重構像這樣:

public class Parent 
{ 
    private Texture2D texture; 

    public Parent(Texture2D texture) { 
     this.texture = texture; 
    } 

    public Texture2D Picture { get { 
      return texture; 
     } 
    } 
} 

public class SubClass1 : Parent 
{ 
    public SubClass1(Texture2D texture) : base(texture) { 

    } 
} 

讓我解釋爲什麼靜態是一個糟糕的選擇:

  1. 你的類現在只爲一個位圖不錯。消除了重用類的幾個位圖的可能性(這是你正在對抗的限制)
  2. 直到調用靜態setter後,你的類纔會處於有效狀態。一般而言,構建的對象應該處於有效狀態。如果他們使用你的對象,他們必須靜態設置類的位圖,這對別人來說並不明顯。
  3. 打破自然垃圾收集。例如,如果您希望在收集SubClass的所有實例時對Texture2D對象進行垃圾收集,則它不適用於您的靜態設計。或者,如果您使用oop設計(如建議),您可以靈活地進行垃圾收集,而不取決於您的使用情況。
  4. 使線程更復雜。靜態屬性是全局的,所以您需要全局互斥來保證線程安全。
  5. 使測試更加困難。如果你想單元測試這個類,你必須確保在每次測試之後靜態被清除,並且你不能同時對這個類運行兩個單元測試。
  6. 使內存管理不靈活。如果您使用面向對象的設計,則可以選擇在所有實例之間共享位圖,或爲每個實例分配一個新的位圖。
+0

我有一個遊戲。父母定義了遊戲的一些一般對象(如座標,移動方法等)。子類是具有已定義屬性的實際對象,但它們的圖片必須從Game類加載。我曾經給他們提供了構建'someObject(int x,int y,Texture2D pic)'的圖片,但將圖片保存到類中似乎更好,所以我不必每次將它發送給構造函數類的實例。 – pavelkomin

+0

構造函數聽起來像是一個更好的方法來實際執行它。不要擔心傳遞引用,因爲它只是一個引用。每次將它傳遞給構造函數時,它都不會複製圖像,所以如果使用構造函數構造它們,您將獲得在所有實例之間共享內存的好處對同一個Texture2D的引用。 – Samuel

0

聽起來像virtual關鍵字的工作。

virtual關鍵字用於修改方法,屬性,索引器或事件聲明,並允許在派生類中重寫它。

https://msdn.microsoft.com/en-us/library/9fkccyh4.aspx

+2

「你不能在靜態,抽象,私有或覆蓋修飾符中使用虛擬修飾符」 – Samuel

+0

正確...它必須重新設計......但我只是說...這就是繼承的目的和虛擬關鍵字。 – kevindeleon

1

你可以用靜態Dictionary<Type,Texture2D>來做到這一點。

public class Parent 
{ 
    // Keep a table of types and default values 
    protected static Dictionary<Type, Texture2D> pictureOrigin; 

    static Parent() 
    { 
     // static ctor. initialize table 
     pictureOrigin=new Dictionary<Type, Texture2D>(); 
    } 

    internal static void SetDefaultPicture<T>(Texture2D picture) 
    { 
     // Set default based on type T 
     Type type=typeof(T); 
     pictureOrigin[type]=picture; 
    } 

    public Parent() 
    { 
     // Assign default based on this type 
     Picture=pictureOrigin[this.GetType()]; 
    } 
    public Texture2D Picture { get; set; } 
} 

public class SubClass1 : Parent 
{ 
} 
public class SubClass2 : Parent 
{ 
} 

用作

static void Main(string[] args) 
    { 
     Texture2D picture0 = Load("pictureForParent"); 
     Texture2D picture1=Load("pictureFroSubClass1"); 
     Texture2D picture2=Load("pictureFroSubClass2"); 

     Parent.SetDefaultPicture<Parent>(picture0); 
     Parent.SetDefaultPicture<SubClass1>(picture1); 
     Parent.SetDefaultPicture<SubClass2>(picture2);    
    } 

下面是一個例子的調試。它顯示SubClass1自動初始化爲pictureForSubClass1

res

相關問題