2009-08-17 4 views
35

WPF 응용 프로그램에서 클래스 계층 구조에 문제가 발생했습니다. 두 개의 상속 트리가 함께 병합되는 문제 중 하나이며, 다중 상속없이 상속을 원활하게 수행 할 수있는 논리적 인 방법을 찾을 수 없습니다. 이 시스템을 작동 시키거나 디버깅하는 것을 불가능하게하지 않으면 서 누군가가 밝은 아이디어를 가지고 있는지 궁금합니다..NET에서 다중 상속에 대한 좋은 대안은 무엇입니까?

필자는 저급 엔지니어이기 때문에 처음 생각하는 것은 항상 "오!이 클래스 중 일부는 기본 C++로 작성하고 외부에서 참조 할 것입니다! 그런 다음 모든 기존 학교 OO 즐거움! " 당신이 관리 컨트롤에서 상속 할 때 아아,이

이 내 현재의 예상 클래스 다이어그램의 조각 표시 허용 ... 도움이되지 않습니다

____________________________________  _____________________________________ 
| CustomizableObject     | | System.Windows.Controls.UserControl | 
|____________________________________| |_____________________________________| 
| string XAMLHeader()    |      ▲ 
| string XAMLFooter()    |◄--┐     | 
| CustomizableObject LoadObject() | \     | 
| <Possible other implementations> | \     | 
|____________________________________|  \     | 
     ▲      ▲   \     | 
     |      |   \    | 
     |      |    \    | 
_________________ ______________________ \ _____________________ 
| SpriteAnimation | | SpriteAnimationFrame | └---| CustomizableControl | 
|_________________| |______________________|  |_____________________| 
                 ▲    ▲ 
                 |    | 
                 |    | 
                ________ _____________ 
               | Sprite | | SpriteFrame | 
               |________| |_____________| 

문제는 아주 분명하다 분리 CustomizableObject 및 CustomizableControl 개체 트리의 --- UserControl을 하나의 트리에 삽입합니다.

클래스에 따라 구현이 다르지 않으므로 CustomizableObject 구현을 파생 클래스로 옮기는 것이 현실적이지 않습니다. 게다가 여러 번 구현하는 것이 정말 혼란 스럽습니다. 따라서 CustomizableObject를 인터페이스로 만들고 싶지는 않습니다. 인터페이스 솔루션은 나에게 전혀 이해가되지 않습니다. (인터페이스는 을 가지지 않습니다.은 솔직히 말해서 제게 많은 감각을주었습니다 ...)

다시 말하면, 누구나 밝은 아이디어가 있습니까? 이건 진짜 피클이야. 인터페이스가 객체 트리가 아닌 객체 트리로 작동하도록하는 방법에 대해 자세히 알고 싶습니다. WPF와 C#을 사용하여 간단한 스프라이트 엔진을 만드는 것입니다. 이것은 C++에서 매우 쉽게 해결할 수 있습니다.하지만 관리 환경에서 이러한 문제를 해결하는 방법을 찾아야합니다. 힘들어 질 때마다 손을 내밀고 Win32로 돌아가는 것이 아닙니다.

+19

+1을 모두 그리기 위해 : – Kamarey

+1

하하, 내 작품을 감상 할 수있어서 기쁩니다. – Giffyguy

+1

이 질문은 stackoverflows Q & A 형식에 잘 맞지 않습니다. "좋은 대안은 무엇인가"는 이미 하나의 정답이 없다고 가정합니다. 다양한 방법과 의견이 있습니다. –

답변

17

한 가지 방법은 System.Linq와 마찬가지로 "파생 클래스"구현을 제공하기 위해 인터페이스와 함께 확장 메서드를 사용하는 것입니다.Queryable에서 :

interface ICustomizableObject 
{ 
    string SomeProperty { get; } 
} 

public static class CustomizableObject 
{ 
    public static string GetXamlHeader(this ICustomizableObject obj) 
    { 
     return DoSomethingWith(obj.SomeProperty); 
    } 

    // etc 
} 

public class CustomizableControl : System.Windows.Controls.UserControl, ICustomizableObject 
{ 
    public string SomeProperty { get { return "Whatever"; } } 
} 

사용법 :만큼 당신에 대한 사용 지침을 (또는 같은 공간에있는) 확장 방법이 정의 된 네임 스페이스로 : 난

var cc = new CustomizableControl(); 
var header = cc.GetXamlHeader(); 
+0

사용법을 추가했다. 당신을위한 예. 컴파일러가 찾을 수있는 한, 확장 메소드는 인스턴스 메소드처럼 보이고 느껴진다. 불행히도 확장 속성이 없으므로 메서드 이름 지정 규칙을 따르는 메서드 이름을 바꿉니다. – dahlbyk

+4

또한 MSDN에서이 기사를 확인하십시오. http://msdn.microsoft.com/en-us/vcsharp/bb625996.aspx – dahlbyk

+0

이 솔루션은 문제를 완벽하게 해결합니다! 그건 정말 멋지다. 여기서 보너스는 객체 트리 내에서 구현을 단일 위치에 유지하는 것입니다. 즉, 객체 트리를 다형 적으로 또는 인터페이스를 통해 확산하는 대신 WPF 컨트롤 사고 방식과 잘 어울립니다. NET에서 다중 상속/인터페이스 문제를 겪고있는 사람에게이 솔루션을 권장합니다. – Giffyguy

1

인터페이스 및 개체 구성에 의존해야합니다.

29

두 가지 옵션이 있습니다. 인터페이스를 사용하거나 컴포지션을 사용하십시오. 솔직히 인터페이스는 매우 강력합니다.이 라인을 읽은 후이 라인을 읽은 후

인터페이스 솔루션은 나에게 이해가 가지 않습니다. (인터페이스는 솔직히 나에게별로 의미가 없었습니다 ...)

제대로 사용하는 법을 배워야한다고 생각합니다. 즉, 여러 클래스가 필요로하는 논리가 있지만 해당 클래스가 동일한 기본 클래스에서 상속 받는다는 의미가 아니라면 해당 논리를 캡슐화하는 클래스를 만들어 해당 클래스의 멤버 변수를 클래스에 추가하면됩니다. 당신에게 문제가되는 것들. 이 방식으로 모든 클래스는 로직을 포함하지만 상속 계층 구조에서 분리 될 수 있습니다. 클래스가 공통 인터페이스를 구현해야한다면 인터페이스를 사용하십시오.

+0

나는 당신이 이것을 묘사하는 방식을 정말 좋아합니다. 아마 "작곡"루트를 택할 것 같습니다. 그것은 복잡하게 짜증나게 할 것이지만, 구현하는 것보다 덜 복잡합니다. (하하, 나는 너무 완고 해 ... 나는 인터페이스에 대한 도움을 SO에게 직접 요청하는 용기를 내고, 나는 여전히 자존심을 삼켜 서 인터페이스의 힘에 대한 모든 조언을 받아 들일 수 없다.) – Giffyguy

7

이것을보고, CustomizableObject은 인터페이스로 만들어지기 위해 비명을 지르고 있습니다 (그리고 모든 구체적인 유형은 객체로 변환 될 수 있기 때문에 이름의 일부는 중복됩니다). 실행중인 문제는 공유되거나 구현에 따라 약간 다를 수있는 기본 논리를 유지하는 방법을 잘 모르고 트리에서이 논리를 저장하여 다형성으로 작동하게하려는 것입니다. 그 단어?).

위임을 통해이를 수행 할 수 있습니다. 나는 정확히 구성원이 더 같은 아마 뭔가를 당신에게 문제를 제공되지만 확실하지 않다 :

____________________________________  _____________________________________ 
| ICustomizable      | | System.Windows.Controls.UserControl | 
|         | |_____________________________________| 
| Func<string> XAMLHeader;   |      ▲ 
| Func<string> XAMLFooter   |◄--┐     | 
| ICustomizabl LoadObject() | \     | 
| <Possible other implementations> | \     | 
|____________________________________|  \     | 
     ▲      ▲   \     | 
     |      |   \    | 
     |      |    \    | 
_________________ ______________________ \ _____________________ 
| SpriteAnimation | | SpriteAnimationFrame | └---| CustomizableControl | 
|_________________| |______________________|  |_____________________| 
                 ▲    ▲ 
                 |    | 
                 |    | 
                ________ _____________ 
               | Sprite | | SpriteFrame | 
               |________| |_____________| 

또한, 당신은 아마 당신이 이 CustomizableObject 유형 속한 정말 기분이 진정으로 정적 어떤 논리를 가지고있다. 그러나 이것은 틀린 것일 수 있습니다. 특정 상황에서 해당 유형을 사용할 의도로 유형을 작성했습니다. 예를 들어 컨텍스트에서 이러한 컨트롤과 애니메이션을 만들고 Windows Form에서 사용하는 것처럼 보입니다. 해야 할 일은 기본 System.Windows.Form을 상속받은 자신 만의 폼을 가지며이 새로운 폼 유형은 ICustomizableObject와이를 사용하는 방법을 알아야합니다. 그것은 당신의 정적 논리가 갈 곳입니다.

이것은 약간 어색한 것처럼 보일 수 있지만 프레젠테이션 엔진을 변경하기로 결정한 경우 정확합니다. 이 코드를 WPF 또는 Silverlight로 이식하면 어떻게됩니까? Windows Forms와 약간 다른 방식으로 구현 코드를 사용해야 할 것이며 CustomizableControl 구현을 변경해야 할 가능성이 높습니다. 하지만 이제 정적 논리가 모두 정확한 위치에 있습니다.

마지막으로, 사용중인 LoadObject() 메서드는 잘못된 위치에서도 마찬가지입니다. 모든 커스터마이징 가능 유형이 자신을로드/구축하는 방법을 알고 호출 할 수있는 메서드를 제공하기를 원한다는 것을 말하고 있습니다. 그러나 이것은 정말로 다른 무엇인가입니다. 또 다른 인터페이스가 IConstructable<T>이고 ICustomizable 유형이 (IConstructable<ICustomizable>)을 구현하도록 할 수 있습니다.

+0

+1 흠 ... 당신은 매우 흥미로운 점을 제기합니다. 내 스프라이트 컨트롤이 자급 자족하기를 정말로 좋아할 것입니다. 이것은 결국 WPF입니다. 따라서 우리는 WinForms에서와 같이 기본 윈도우 유형을 상속받지 않아야합니다.하지만이 솔루션을 SpriteLayer 또는 SpriteView 컨트롤에 쉽게 적용 할 수 있습니다. – Giffyguy

+1

나는 대표자 접근법을 정말 좋아한다. 실제로 코딩 할 때 약간의 시간을 들여서 대리인이이를 위해 어떻게 작동하는지 보려고했습니다. 일단 컴파일하고 실행하면 대답을 받아 들일 계획이었습니다. 확장 메서드가 더 잘 작동하고 깨끗하다고 ​​생각합니다.그러나 이것은 분명히 주목할 가치가있는 훌륭한 솔루션입니다. 사실, 대의원들이 확장 방법보다 더 나은 문제를 해결할 수있는 많은 사례가있을 것이라는 것을 기꺼이 확신합니다. – Giffyguy

1

그런 경우에는 믹스 인을 사용합니다. mixins는 런타임에 클래스에 기능을 추가하는 데 사용되는 강력한 개념입니다. 믹스 인은 여러 언어로 잘 알려져 있습니다. 리믹스 프레임 워크는 mixin 기술을 .NET으로 가져 오는 프레임 워크입니다.

아이디어는 간단합니다. 클래스를 믹스 인을 나타내는 클래스 속성으로 꾸미십시오. 런타임에이 기능이 클래스에 추가됩니다. 따라서 다중 상속을 에뮬레이션 할 수 있습니다.

문제의 해결책은 CustomizableObject를 mixin으로 만드는 것일 수 있습니다. 이를 위해 다시 믹스 프레임 워크가 필요합니다.

[사용 (CustomizableObjectMixin)]을 CustomizableControl : UserControl을이

자세한 내용은 remix.codeplex.com를 확인하시기 바랍니다.

1

나는 해결책 중 하나라고 생각합니다.

public interface IClassA 
{ 
    void Foo1(); 
    void Foo2(); 
} 

public interface IClassB 
{ 
    void Foo3(); 
    void Foo4(); 
} 

public class ClassA :IClassA 
{ 
    #region IClassA Members 

    public void Foo1() 
    { 
    } 

    public void Foo2() 
    { 
    } 

    #endregion 
} 

public class ClassB :IClassB 
{ 
    #region IClassB Members 

    public void Foo3() 
    { 
    } 

    public void Foo4() 
    { 
    } 

    #endregion 
} 

public class MultipleInheritance :IClassA, IClassB 
{ 
    private IClassA _classA; 
    private IClassB _classB; 

    public MultipleInheritance(IClassA classA, IClassB classB) 
    { 
     _classA = classA; 
     _classB = classB; 
    } 

    public void Foo1() 
    { 
     _classA.Foo1(); 
    } 

    public void Foo2() 
    { 
     _classA.Foo2(); 
     AddedBehavior1(); 
    } 

    public void Foo3() 
    { 
     _classB.Foo3(); 
     AddedBehavior2(); 
    } 

    public void Foo4() 
    { 
     _classB.Foo4(); 
    } 

    private void AddedBehavior1() 
    { 

    } 

    private void AddedBehavior2() 
    { 

    } 
} 

클래스 다중 상속이 개체의 동작에 영향을주지 않고 두 개의 다른 개체에 새 동작을 추가합니다. 다중 상속은 전달 된 객체와 동일한 비헤이비어를가집니다 (두 비헤이비어 모두 상속). 나의 영어를위한 Sory. 문안 인사.

+0

데코레이터 패턴으로 보지 않습니다. –

+0

나는 이것이 당신이을 downvoted 이유, 내가 볼 수없는 _some_ 상황에서 유효하고 가능한 접근이라고 생각합니다. 외관상으로는 데코레이터가 기존 클래스를 확장하기 때문에 일반적인 접근 방식이 아닙니다. 데코레이터 유형을 직접 사용할 수도 있지만 완전히 새로운 방법을 추가 할 수도 있습니다. 장식 자 패턴이 아니라는 것을 볼 수 있지만 구성의 변형으로 작동 할 수 있습니다. – julealgon

관련 문제