2009-12-15 89 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

相关问题