컴포지션을 통해 인터페이스를 구현하는 클래스에서 상용구 줄이기


11

나는 수업이 : A작은 클래스의 수의 합성이다 B, C하고 D.

B, CD인터페이스를 구현 IB, ICID각각.

이후 A의 모든 기능 지원 B, CD, A구현 IB, IC그리고 ID뿐만 아니라,하지만 많은이 불행하게도 리드의 구현에 재 라우팅A

이렇게 :

interface IB
{
    int Foo {get;}
}

public class B : IB
{
    public int Foo {get {return 5;}}
}

interface IC
{
    void Bar();
}

public class C : IC
{
    public void Bar()
    {
    }
}

interface ID
{
    string Bash{get; set;}
}

public class D: ID
{
    public string Bash {get;set;}
}

class A : IB, IC, ID
{
    private B b = new B();
    private C c = new C();
    private D d = new D();

    public int Foo {get {return b.Foo}}

    public A(string bash)
    {
        Bash = bash;
    }

    public void Bar()
    {
        c.Bar();
    }

    public string Bash
    {
         get {return d.Bash;}
         set {d.Bash = value;}
    }
}

이 상용구 리디렉션을 제거하는 방법이 A있습니까? B, CD모든 다르지만 일반적인 기능을 구현하고, I처럼 A구현 IB, ICID그 의미 때문에 전달할 수있는 A이러한 인터페이스 일치 의존성 자체 및 내부 헬퍼 메소드를 노출 할 필요가 없다.


IB, IC, ID를 구현하기 위해 클래스 A가 필요한 이유에 대해 조금 말씀해 주시겠습니까? 왜 BCD를 공개로 공개하지 않습니까?
Esben Skov Pedersen

1
내가 선호 내 가장 큰 이유라고 생각 A구현을 IB, IC그리고 ID그것을 쓰기에 더 분별있는 느낌입니다 Person.Walk()반대로 Person.WalkHelper.Walk()예를 들어,.
Nick Udell

답변:


7

당신이 찾고있는 것은 일반적으로 mixins 라고 합니다. 안타깝게도 C #은 기본적으로 지원하지 않습니다.

몇 가지 해결 방법이 있습니다. 하나 , , 및 그 이상.

나는 실제로 마지막을 좋아합니다. 상용구를 생성하기 위해 자동으로 생성 된 부분 클래스를 사용하는 아이디어는 아마도 실제로 좋은 해결책에 도달 할 수있는 가장 가까운 것입니다.

[pMixins]는 pMixin 속성으로 장식 된 부분 클래스에 대한 솔루션을 검색하는 Visual Studio 플러그인입니다. [pMixins]는 클래스를 부분적으로 표시하여 코드 숨김 파일을 만들고 클래스에 멤버를 추가 할 수 있습니다.


2

코드 자체에서 상용구를 줄이지 않지만 Visual Studio 2015에는 이제 자동으로 상용구를 생성 할 수있는 리팩토링 옵션이 제공됩니다.

이것을 사용하려면 먼저 인터페이스 IExample와 구현을 만드십시오 Example. 그런 다음 새 클래스 Composite를 만들고 상속 시키되 IExample인터페이스를 구현하지 마십시오.

유형의 속성이나 필드를 추가 Example하여에 Composite, 클래스 토큰에 대한 빠른 조치 메뉴를 열고 IExample당신의 Composite클래스 파일과 " '예'를 통해 인터페이스를 구현합니다"를 선택,이 경우 '예'필드 또는 속성의 이름입니다.

Visual Studio는 인터페이스에 정의 된 모든 메서드와 속성을 생성하고이 도우미 클래스로 리디렉션하지만이 답변이 게시 된 시점의 이벤트는 리디렉션 하지 않습니다 .


1

수업이 너무 많으니 보일러 플레이트를 너무 많이 구현해야합니다. 당신은 의견에 말합니다 :

Person.WalkHelper.Walk ()와 반대로 Person.Walk ()를 작성하는 것이 더 합리적입니다.

동의하지 않습니다. 걷기 행위는 많은 규칙을 포함 할 가능성이 높으며 Person클래스에 속하지 않습니다 . 이는 Person이 구현 WalkingService하는 walk(IWalkable)메소드가 있는 클래스에 속합니다 IWalkable.

코드를 작성할 때는 항상 SOLID 원칙을 명심하십시오. 여기서 가장 적용 가능한 두 가지는 우려 분리 (보행 코드를 별도의 클래스로 추출)와 인터페이스 분리 (인터페이스를 특정 작업 / 기능 / 능력으로 분할)입니다. 여러 인터페이스가있는 I 중 일부가있을 수 있지만 하나의 클래스로 구현하여 모든 훌륭한 작업을 취소합니다.


내 예제에서 기능 별도의 클래스 구현되며 필요한 동작을 그룹화하는 방법으로 이들 중 몇 가지로 구성된 클래스가 있습니다. 더 큰 클래스에는 실제 구현이 없으며 더 작은 구성 요소로 처리됩니다. 어쩌면 당신이 옳을 수도 있고, 도우미 클래스를 공개하여 직접 상호 작용할 수 있도록하는 것이 좋습니다.
Nick Udell

4
walk(IWalkable)방법 의 아이디어에 관해서는, 걷는 서비스가 사람이 아닌 호출자의 책임이되고 일관성이 보장되지 않기 때문에 개인적으로 싫어합니다. 모든 호출자는 일관성을 보장하기 위해 어떤 서비스를 사용해야하는지 알아야하지만 Person 클래스에 유지하면 도보 거동이 달라 지도록 수동으로 변경해야하지만 종속성 반전은 허용됩니다.
Nick Udell

0

당신이 찾고있는 것은 다중 상속입니다. 그러나 C #이나 Java에는 없습니다.

A에서 B를 확장 할 수 있습니다. 이렇게하면 리디렉션 접착제뿐만 아니라 B에 대한 개인 필드가 필요하지 않습니다. 그러나 B, C 또는 D 중 하나에 대해서만이 작업을 수행 할 수 있습니다.

이제 C를 B에서 상속하고 D를 C에서 상속 할 수 있다면 A 확장 D ...;) 만 있으면됩니다.하지만 분명히하기 위해이 예제에서는 실제로 표시가 없기 때문에 권장하지 않습니다. 그것을 위해.

C ++에서는 A가 B, C 및 D에서 상속받을 수 있습니다.

그러나 다중 상속은 프로그램을 추론하기 어렵게 만들고 자체 문제가 있습니다. 또한이를 피할 수있는 깨끗한 방법이 종종 있습니다. 그럼에도 불구하고 때로는 그것 없이는 반복되는 상용구와 객체 모델이 노출되는 방식 사이에서 설계의 절충점을 만들어야합니다.

구성과 상속을 혼합하려는 것처럼 느껴집니다. 이것이 C ++ 인 경우 순수한 상속 솔루션을 사용할 수 있습니다. 그러나 그것이 작곡을 포용하는 것은 좋지 않습니다.


2
op가 예제 코드에서했던 것처럼 java와 c #의 인터페이스를 사용하여 다중 상속을 가질 수 있습니다.
Robert Harvey

1
일부는 C ++ 에서처럼 다중 상속과 동일한 인터페이스를 구현하는 것을 고려할 수 있습니다. 인터페이스가 상속 가능한 인스턴스 메소드를 제시 할 수 없기 때문에 다른 의견에 동의하지 않을 수 있는데, 이는 다중 상속이있는 경우의 것입니다. C #에서, 당신은 당신이 ... 모든 보일러가 필요한 이유이다, 따라서 여러 클래스로부터 상속 인스턴스 메소드 구현은 할 수없는, 여러 개의 기본 클래스를 확장 할 수 없습니다
에릭 Eidt

그 다중 상속이 나쁜 동의하지만, 여러 개의 인터페이스 구현 단일 상속의 C # / 자바의 대안은 만병 통치약이 (가없는 것은 아니다 인터페이스 전달 이 인체 공학적 악몽). Golang과 함께 시간을 보낸 후 Go가 상속 을 받지 않고 인터페이스 전달을 사용하는 구성에 전적으로 의존하는 것에 대한 올바른 아이디어를 얻었 지만 특정 구현에도 문제가 있다고 생각합니다. 내가 생각하는 최고의 인터페이스로 모든 유형을 사용할 수있는 능력과, 포워딩, (아무도 아직 구현 한 것 같다) 솔루션 구성입니다.
다이
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.