2013-10-01 52 views
3

我正在做一個遺留應用程序,因爲繼承有一些缺陷,但我正在努力解決它。在C#winforms中消除繼承「魔術」的最佳方法是什麼?

此刻的WinForms的結構是這樣的:

  • BaseForm
  • ListViewForm : BaseForm
  • ListViewFormReadOnly : ListViewForm
  • ListViewFormWithDetailForm : ListViewForm
  • DetailForm : BaseForm
  • ConcreteForm : ListViewFormWithDetailForm

BaseForm裏面有一個方法叫做sth,像protected virtual void InitializeMyStuff()這個被覆蓋在繼承的實例中。

例如

public class BaseForm { 
    public BaseForm() { 
     //.. do stuff 

     //.. do other stuff like initialize DB connection or read app.config values and initialize properties.. 
} 

public virtual void InitializeMyStuff() { 
     throw new NotImplementedException(); 
    } 
} 

public class ListViewForm : BaseForm { 
    protected BindingSource GridBindingSource { get; set; } 

    public ListViewForm { 
     //do special stuff like adding the grid and some buttons 
    } 
} 
public class ConcreteForm : ListViewForm { 
public override void InitializeMyStuff() { 
     GridBindingSource = my_bindingSource; 
     SomeOtherUsefulProperty = myValue; 
     Foo = new Bar(); 
     // etc. 
    } 
} 

//Usage: 
var myForm = new ConcreteForm(); 
myForm.InitializeMyStuff(); 

正如你能想象這產生了一些問題,如: - 「我有什麼事情要設定在這一點上的形式合作」 - 「什麼事情可能還沒有被初始化?」 - 「哪些屬性和方法調用仍在使用中」 以及關於該魔法黑盒中可能發生的一些其他有趣想法。

我該如何重構這個,使其更清楚發生了什麼?請記住,這是一個包含約150個或更多具體表單的項目。

我最初的想法是將例如GridBindingSource這些神奇屬性封裝到一個對象中(例如FormConfiguration),並使其在BaseForm中保密。

例如類似的東西

public class BaseForm { 
    private FormConfigObject _formConfig = new FormConfigObject(); 

    protected override void OnLoad() 
    { 
     InitializeMyStuff(_formConfig); 
    } 

    protected virtual void InitializeMyStuff(FormConfigObject config) 
    {} 
} 

的問題,我這裏是:ListForm的FormConfig對象就必須有例如其他屬性,如GridBindingSource但我不能只是改變在派生類中籤名的ListFormConfigObject是不是FormConfigObject ..

有人可以建議可能的解決方案擺脫這種困境?

//編輯:將代碼簡化爲實際發生的事情,並在構造函數違規中擺脫虛擬調用。

+2

這也違反了'CA2214'規則:http://msdn.microsoft.com/en-us/library/ms182331.aspx - 虛擬方法不應該在構造函數中調用。 – BartoszKP

+0

你有什麼好的理由去改變它嗎?起初,我的想法是刪除所有'InitializeMyStuff',一個虛擬調用ctor是一個壞主意,但這是很多工作。 –

+1

這個問題可能是更適合http://codereview.stackexchange.com/ –

回答

3

的主要問題是:是否存在內部BaseForm任何對象:

  • 需要在BaseForm的構造函數初始化
  • 依賴於具體實現的子類

如果存在這樣的對象,那麼可能它們應該是多態的,並從子類傳入BaseForm的構造函數。

一個簡單的例子,對許多可能的情況:

abstract class RandomPicture 
{ 
    public RandomPicture() 
    { 
     shapes = new List<Shape>(); 
     InitializeRandomShapes(); 

     // do some initial drawing calculations 
    } 

    protected abstract void InitializeRandomShapes(); 

    protected List<Shape> shapes; 
} 

//... subclasses initialize the shapes 

這可以更改爲:

abstract class RandomPicture 
{ 
    public RandomPicture(AbstractShapeCollection shapeCollection) 
    { 
     shapes = shapeCollection; 

     // do some initial drawing calculations 
    } 

    private AbstractShapeCollection shapes; 
} 

現在子類提供通過抽象對象所需的信息,所以基類可以繼續完成它的任務。

拆分成信息像這樣的各種對象是一個好的開始重構,爲您創造更多更小的物體,更易於測試和管理,並表明你已經遇到了亂七八糟的底層結構。它也有助於減少違反Single Responsibility Principle的次數。

+0

我編輯了我的問題以解決編寫示例時出現的一些錯誤。實際上在構造函數中沒有虛擬調用,因爲初始化是從外部調用的....:/ – bberger

+0

@bberger我已經從回答中刪除了有關規則的信息。但我認爲它幾乎保持不變 - 重構成更小的對象。 'OnLoad'就像一個構造函數,所以原則上我會建議相同的場景。 – BartoszKP

+0

是啊,這是我會做什麼時,我可以從頭開始 - 但是這將是太多的公司重構沒有人會贊同:/我需要爲這個另一種解決方案:/ – bberger

相關問題