2012-05-23 18 views
2

因此,對於繼承,我始終會發現自己處理最特定類中的極長構造函數。我正在尋找一種可以避免這個問題的範式或方法。我想過使用工廠,但如果我這樣做了,我仍然必須在工廠中使用構造函數。不管那個想法,有什麼我可以做的,以保持構造參數長度下來?使用OOP繼承我如何在「子」類中保持較低的參數

例如:

abstract class DrawableComponent : Component, ITransformable, IScalable, IDrawable, IRotatable 

是兒童類構造函數像

DrawableComponent(string Name, int SizeX, int SizeY, int X, int Y, float Rotation) : base(Name) { ... } 

現在,讓我們說,我想做出一個孩子。事情變得更加複雜和醜陋。

class TextBoxComponent : DrawableComponent, IRenderable 

構造函數現在變得非常長:

public TextBoxComponent(
    IDrawableUnit Background, 
    IDrawableUnit Text, 
    string Name, 
    int X, 
    int Y, 
    int SX, 
    int SY) 
: base(Name, SX,SY,X,Y,0.0f) 
{ 
    this.Background = Background; 
    this.Foreground = Foreground; 
} 

在這個總結,我看了就討厭這樣的事情的:

class Blah {Blah(blah)} 
class childBlah : Blah {childBlah(blah,blahs,blaha) : base (blah)} 
class grandChildBlah : childBlah {grandChildBlah(blah, blahs, blaha, blaht, blauh) : base(blah,blahs,blaha) } 
+0

極其長的構造函數正在做什麼? –

+1

使用您最喜愛的IoC容器/ DI框架。這是依賴注入解決的許多問題之一。 – Kane

+0

@Kane - 雖然構造函數DI解決了需要「服務」的類的問題,但它並沒有解決任何帶有值的構造函數,例如示例中的值。 – Lucero

回答

5

如果你有很長的構造函數參數列表,那麼你必須在一個類中有很多字段?這表明您應該考慮將這些類拆分爲多個類,或將相關字段的組提取爲它們自己的類型。

例如,x和y座標的字段或寬度和高度值:

private double mX; 
private double mY; 
private double mWidth; 
private double mHeight; 

真的應該是單個點或載體或矩形對象:

private vector mPosition; 
private vector mSize; 

// or 

private rectangle mRegion; 

另一個建議可能是減少你的繼承,而是使用組合。取而代之的是-A關係,使用具有-A關係:然後

你 '嗒嗒' 例如成爲類似:

class Blah 
{ 
    Blah(int blah) { ... } 
} 

class ChildBlah 
{ 
    Blah mBlah; 
    ... 
    ChildBlah(Blah blah, int blahs, int blaha) 
    { mBlah = blah; ... } 
} 

class GrandChildBlah 
{ 
    ChildBlah mChildBlah; 
    ... 
    GrandChildBlah(ChildBlah blah, int blaht, int blahu) 
    { mChildBlah = blah; ... } 
} 
+0

+1。繼承往往看起來像是一種方式,但最終導致頭痛。保持類 - 甚至是繼承的子類 - 很簡單。 –

2

是的,你可以使用Builder模式。至少,這會將構造函數的調用限制在一個類中。例如:

VehicleBuilder builder = new VehicleBuilder(); 
builder.setColor(Color.Green); 
builder.setEngineSize(EngineSize.Size1500); 
builder.setWheelSize(14); 
Vehicle auto = builder.makeVehicle(); 

另一種可能性是將這些參數中的一些分成類。即使你創建了一個不可變的對象,如果你製作了防禦性的副本,它也可以餵食可變參數。

VehicleParameters parameters = new VehicleParameters(); 
parameters.setColor(Color.Green); 
parameters.setEngineSize(EngineSize.Size1500); 
parameters.setWheelSize(14); 
Vehicle auto = new Vehicle(parameters); 
0

有幾件事情可以做。 constructor chainingoptional arguments

構造函數鏈本質上意味着你有一個默認的構造函數,然後爲每個附加參數再多一個構造函數,或者根據需要。

像這樣:

class Class1 
{ 
    private string name, jobTitle, address; 

    public Class1(string name, string title) 
     : this(name, title, "my default address") {} 

    public Class1(string name, string jobTitle, string address) 
    { 
     this.name = name; 
     this.jobTitle = jobTitle; 
     this.address = address; 
    } 
} 

另一個選項是可選的參數,就像這樣:

class Class1 
{ 
    private string name, jobTitle, address; 

    public Class1(string name = "default", string jobTitle = "defaultJob", string address = "defaultAddress") 
    { 
     this.name = name; 
     this.jobTitle = jobTitle; 
     this.address = address; 
    } 
} 

記住必需的參數必須在可選參數總會來。

0

您可以通過傳遞包含您感興趣的屬性的鍵值對的字典來緩解痛苦。爲了提高可讀性和語法,本字典可以從匿名類構建,就像ASP之類的庫一樣.NET MVC爲很多方法調用執行此操作。

然後你會在每個級別有兩個構造函數:受保護的獲取字典和公開的獲取匿名對象,該對象本身總是將匿名對象轉換爲字典時調用受保護的構造函數。

public class Class1 { 
    public Class1(object args): this(new RouteValueDictionary(args)) {} 

    protected Class1(RouteValueDictionary args) { 
    // retrieve any property you need here from args 
    } 
} 

public class Class2: Class1 { 
    public Class2(object args): this(new RouteValueDictionary(args)) {} 

    protected Class2(RouteValueDictionary args): base(args) { 
    // retrieve any property specific to Class2 from args 
    } 
} 

// etc. 

使用此類似:

new Class2(new { 
    X: 10, 
    Y: 20, 
    Name: "instance" 
    }); 

的優點是,這給你一個很好的語法,無論有多少ARG遊戲傳入,你也可以省略參數或創建非常動態的「過載「的構造函數。這種方法的主要問題是,編譯器無法在編譯時告訴你需要傳遞給構造函數的內容(例如,你失去了一些靜態分析的好處)。

注意:此處用於解析的RouteValueDictionary不是MVC項目的一部分,而是System.Web程序集的一部分,因此可以在任何已部署完整.NET框架的地方隨時使用。它確實有效地處理匿名類型提取,通常比自己手動反映更好。