2009-12-15 92 views
0

我正在爲3D建模程序編寫一個插件。我有一個自定義的類,它包裝3D模型中的元素實例,並依次從它包裝的元素派生它的屬性。當模型中的元素髮生變化時,我希望我的類根據新的幾何體更新它們的屬性。有沒有辦法自動調用所有版本的繼承方法?

在下面的簡化示例中。我有AbsCurveBasd類,Extrusion和Shell類,它們都是相互派生的。這些類中的每一個都實現了一個RefreshFromBaseShape()方法,該方法根據類正在包裝的當前baseShape更新特定屬性。

我可以在RefreshFromBaseShape()的每個實現中調用base.RefreshFromBaseShape()以確保更新所有屬性。但是我想知道是否有更好的方法,我不必記得在RefershFromBaseShape()的每個實現中都這樣做?例如,因爲AbsCurveBased沒有無參數構造函數,代碼甚至不會編譯,除非構造函數調用基類構造函數。

public abstract class AbsCurveBased 
{ 
    internal Curve baseShape; 
    double Area{get;set;} 

    public AbsCurveBased(Curve baseShape) 
    { 
     this.baseShape = baseShape; 
     RefreshFromBaseShape(); 
    } 

    public virtual void RefreshFromBaseShape() 
    { 
     //sets the Area property from the baseShape 
    } 
} 


public class Extrusion : AbsCurveBased 
{ 
    double Volume{get;set;} 
    double Height{get;set;} 

    public Extrusion(Curve baseShape):base(baseShape) 
    { 
     this.baseShape = baseShape; 
     RefreshFromBaseShape(); 
    } 

    public override void RefreshFromBaseShape() 
    { 
     base.RefreshFromBaseShape(); 
     //sets the Volume property based on the area and the height 
    } 
} 


public class Shell : Extrusion 
{ 
    double ShellVolume{get;set;} 
    double ShellThickness{get;set;} 

    public Shell(Curve baseShape): base(baseShape) 
    { 
     this.baseShape = baseShape; 
     RefreshFromBaseShape(); 
    } 

    public void RefreshFromBaseShape() 
    { 
     base.RefreshFromBaseShape(); 
     //sets this Shell Volume from the Extrusion properties and ShellThickness property 
    } 
} 

回答

0

你這樣做的方式是一個非常典型的模式,它肯定沒有錯 - 它是這樣的事情通常是如何完成的。無法強制執行此調用,因爲推定發生的時間和地點總是由實施者決定。如果你是在逼真的熱衷,那麼你應該考慮使用受保護的事件,而不是:

public abstract class AbsCurveBased 
{ 
    internal Curve baseShape; 
    double Area{get;set;} 

    public AbsCurveBased(Curve baseShape) 
    { 
     this.baseShape = baseShape; 
     RefreshFromBaseShape(); 
    } 

    public void RefreshFromBaseShape() 
    { 
     //sets the Area property from the baseShape 
     ... 

     // call child handlers 
     var handler = RefreshingFromBaseShape; 
     if (handler != null) 
      handler(); 
    } 

    protected event Action RefreshingFromBaseShape; 
} 

public class Shell : Extrusion 
{ 
    double ShellVolume{get;set;} 
    double ShellThickness{get;set;} 

    public Shell(Curve baseShape): base(baseShape) 
    { 
     this.RefreshingFromBaseShape += RefreshingFromBaseShapeHandler; 

     this.baseShape = baseShape; 
     RefreshFromBaseShape(); 
    } 

    private void RefreshingFromBaseShapeHandler() 
    { 
     //sets this Shell Volume from the Extrusion properties and ShellThickness property 
    } 
} 

這樣繼承鏈中任何一類只有在它的處理程序(一個或多個)控制,並不能註銷的處理程序他的祖先,或在祖先插入他們之前將它們插入鏈中。

不過,對於您的特殊情況,這似乎太複雜了,不值得。

此外,如果RefreshFromBaseShape只從構造函數調用,那麼它可能應該是該構造函數的參數。考慮:

public abstract class AbsCurveBased 
{ 
    internal Curve baseShape; 
    double Area{get;set;} 

    public AbsCurveBased(Curve baseShape) 
    { 
     this.baseShape = baseShape; 

     //sets the Area property from the baseShape 
    } 

    protected AbsCurveBased(Curve baseShape, Action refreshFromBaseShape): 
     this(baseShape) 
    { 
     refreshFromBaseShape(); 
    } 
} 

public class Shell : Extrusion 
{ 
    double ShellVolume{get;set;} 
    double ShellThickness{get;set;} 

    public Shell(Curve baseShape): 
     base(baseShape, RefreshFromBaseShape) 
    { 
    } 

    protected Shell(Curve baseShape, Action refreshFromBaseShape): 
     this(baseShape) 
    { 
     refreshFromBaseShape(); 
    } 

    private void RefreshFromBaseShape() 
    { 
     //sets this Shell Volume from the Extrusion properties and ShellThickness property 
    } 
} 
+0

啊,是啊我在想我有什麼事情可以做,涉及事件或分立。但是,這並沒有讓事情變得簡單,只是使用base.RefreshFromBaseShape() – 2009-12-16 00:20:27

+0

它並沒有讓它變得更簡單。它只是保證沒有派生類能夠跳過他的祖先提供的代碼(儘管它仍然可以切斷它的任何後代)。 – 2009-12-16 00:46:56

0

我不確定爲什麼你想要一個單獨的虛擬方法來做到這一點。爲什麼每個類都不能在自己的構造函數中進行計算?在你的例子中,Area將在AbsCurveBased的構造函數中計算;卷&擠出構造函數中的高度等

一般來說,從構造函數調用虛函數是個壞習慣,因爲虛函數在構造函數完成之前會在子類中調用。因此,子類中的方法正在運行,而對象只是部分通過構建。評論

在這種情況下,後

更新我會在每個班的私人DoCalculate()方法。這將由構造函數調用,並且還會在構造函數中不再調用RefreshFromBaseShape()。這並不能減輕你的基本呼叫的需求,這是一種正常模式。

+0

我需要計算對象實例化時的屬性,但如果基礎形狀發生更改,也會在稍後進行計算。 – 2009-12-16 00:22:52

相關問題