2009-12-15 4 views
0

3D 모델링 프로그램 용 플러그인을 작성하고 있습니다. 3D 모델에서 요소의 인스턴스를 래핑하고 래핑하는 요소에서 속성을 가져 오는 사용자 지정 클래스가 있습니다. 모델의 요소가 변경되면 내 수업 (들)이 새 지오메트리를 기반으로 속성을 업데이트하기를 원합니다.상속 된 메서드의 모든 버전을 자동으로 호출하는 방법이 있습니까?

아래의 단순화 된 예에서. AbsCurveBasd, Extrusion, Shell은 모두 서로에게서 파생됩니다. 이러한 각 클래스는 클래스가 래핑중인 현재 baseShape를 기반으로 특정 속성을 업데이트하는 RefreshFromBaseShape() 메서드를 구현합니다.

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

당신이 매우 일반적인 패턴이며, 그것은 아무 문제가 확실히 없다 할 방법 - 그것은 그런 일이 일반적으로 수행하는 방법이다. 언제 어디서 일어 났는지는 항상 구현 자에게 달려 있다는 가정하에 base 호출을 강제로 실행할 방법이 없습니다.

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()를 사용하는 것보다 더 단순하게 만들지는 않습니다. –

+0

단순하지는 않습니다. 파생 된 클래스가 조상이 제공 한 코드를 건너 뛸 수 없도록 보장합니다 (그래도 자손 중 하나를자를 수는 있지만). –

0

왜 이렇게 별도의 가상 방법을 원하십니까? 각 클래스가 자체 생성자에서 계산을 수행 할 수없는 이유는 무엇입니까? 귀하의 예제에서 Area는 AbsCurveBased 생성자에서 계산됩니다. 볼륨 압출 생성자의 높이 등

일반적으로 가상 함수는 생성자가 완료되기 전에 하위 클래스에서 호출되므로 생성자에서 가상 함수를 호출하는 것은 바람직하지 않습니다. 따라서 객체가 부분적으로 생성되는 동안 하위 클래스의 메서드가 실행됩니다. 이 경우 코멘트

업데이트 나는 각 클래스에서 개인 DoCalculate() 메소드를 가질 것이다. 이것은 생성자와 더 이상 생성자에서 호출되지 않는 RefreshFromBaseShape()에 의해 호출됩니다. 그것은 당신의 기본 호출을 연결하는 필요성을 완화하지는 못하지만, 그것은 정상적인 패턴입니다.

+0

개체를 인스턴스화 할 때 속성을 계산해야하지만 나중에 기본 모양이 변경되는 경우 나중에 잠재적으로 변경됩니다. –

관련 문제