데이터 유형에 인터페이스를 사용하는 것이 안티 패턴입니까?


9

사용자, 제품, 송장 및 주문과 같이 모델에 EF를 사용하는 다양한 엔터티가 있다고 가정합니다.

엔티티가 사전 결정된 세트에 속하는 응용 프로그램에서 엔티티 객체의 요약을 인쇄 할 수있는 사용자 정의 컨트롤을 작성 중입니다.이 경우 사용자 및 제품 요약을 요약 할 수 있다고 말합니다.

요약에는 모두 ID와 설명 만 포함되므로 이에 대한 간단한 인터페이스를 만듭니다.

 public interface ISummarizableEntity {     
       public string ID { get; }    
       public string Description { get; } 
 }

그런 다음 해당 엔터티에 대해이 인터페이스를 구현하는 부분 클래스를 만듭니다.

public partial class User : ISummarizableEntity
{
    public string ID
    {
        get{ return UserID.ToString(); }
    }

    public string Description 
    {
        get{ return String.Format("{0} {1} is from {2} and is {3} years old", FirstName, LastName, Country, Age); }
    }
}

public partial class Product: ISummarizableEntity
{
    public string ID
    {
        get{ return ProductID.ToString(); }
    }

    public string Description 
    {
        get{ return String.Format("{0} weighs {1}{2} and belongs in the {3} department", ProductName, WeightValue, WeightUnit, Department); }
    }
}

이 방법으로 내 사용자 제어 / 부분보기는 ISummarizableEntity 컬렉션에 바인딩 할 수 있으며 소스에 전혀 관심이 필요하지 않습니다. 인터페이스를 데이터 유형으로 사용해서는 안되지만 그보다 더 많은 정보를 얻지 못했다고 들었습니다. 내가 알 수있는 한, 인터페이스는 일반적으로 동작을 설명하지만 속성은 getters / setters의 구문 설탕이므로 속성을 사용하는 것은 그 자체로 반 패턴이 아닙니다.

구체적인 데이터 유형을 만들고 엔터티에서 해당 유형으로 매핑 할 수는 있지만 이점을 볼 수는 없습니다. 엔터티 개체를 추상 클래스에서 상속하도록 설정 한 다음 속성을 정의 할 수 있지만 여러 상속을 가질 수 없으므로 엔터티를 더 이상 사용하지 않도록 잠급니다. 원하는 경우 객체를 ISummarizableEntity로 사용할 수 있습니다 (명확하게 인터페이스의 이름을 바꿉니다)

내가 생각하는 솔루션은 유지 관리 가능하고 확장 가능하며 테스트 가능하며 상당히 강력합니다. 반 패턴을 볼 수 있습니까?


와 같은 것을 EntitySummary가지고 User있고 Product각각과 같은 방법 을 갖는 것보다 이것을 선호하는 이유가 public EntitySummary GetSummary()있습니까?
Ben Aaronson

@Ben, 당신은 유효한 옵션을 제안합니다. 그러나 여전히 호출자에게 객체에 GetSummary () 메소드가있을 것으로 예상 할 수 있음을 알리는 인터페이스 정의가 필요합니다. 구현시 모듈화 수준이 추가 된 것과 본질적으로 동일한 디자인입니다. 요약이 소스와 별도로 (단순히) 독립적으로 유지되어야하는 경우에도 좋은 아이디어 일 수 있습니다.
Kent A.

@KentAnderson 동의합니다. 이러한 클래스의 전체 인터페이스와 요약 사용 방법에 따라 실제로 좋은 아이디어 일 수도 있고 아닐 수도 있습니다.
Ben Aaronson

답변:


17

인터페이스는 동작을 설명하지 않습니다. 때로는 정반대입니다.

인터페이스는 "ISummarizableEntity를 허용하는 메소드에이 오브젝트를 제공하는 경우이 오브젝트는 자체 요약 할 수있는 엔티티 여야합니다"와 같은 계약을 설명합니다. 문자열 ID 및 문자열 설명.

인터페이스를 완벽하게 사용합니다. 반 패턴은 없습니다.


2
"인터페이스는 행동을 설명하지 않습니다." "자체 요약"은 어떻게 동작하지 않습니까?
Doval

2
OO 순수 주의자 관점에서 상속 된 @ThomasStringer는 공통 조상을 의미합니다 (예 : 정사각형 은 모두 모양입니다 ). OP의 예에서 사용자와 제품은 합리적인 공통 조상을 공유하지 않습니다. 이 경우 상속은 명확한 반 패턴입니다.
Kent A.

2
@ Doval : 인터페이스 이름이 예상되는 동작을 설명 할 수 있습니다. 그러나 그럴 필요는 없습니다. 인터페이스의 이름은 IHasIdAndDescription으로 동일하게 정할 수 있으며 대답은 동일합니다. 인터페이스 자체는 동작을 설명하지 않고 기대치를 설명합니다.
pdr

2
@pdr 헤드폰 잭을 통해 20V를 보내면 나쁜 일이 발생합니다. 모양이 충분하지 않습니다. 어떤 종류의 신호가 해당 플러그를 통해 올 것인지에 대한 매우 현실적이고 중요한 기대가 있습니다. 이것이 바로 인터페이스에 동작 사양이없는 척하는 것이 잘못된 이유입니다. List목록처럼 동작하지 않는 으로 무엇을 할 수 있습니까?
Doval

3
적절한 인터페이스가있는 전기 플러그가 콘센트에 맞을 수 있지만 이것이 전기를 원하는 것은 아닙니다 (원하는 동작).
JeffO

5

여러 가지 다른 유형의 객체에 필요한 특정 유형의 동작을 정의하고 있기 때문에이 디자인에 더 적합한 경로를 선택했습니다. 이 경우 상속은 실제로 존재하지 않는 클래스 간의 공통 관계를 의미합니다. 이 경우 상속보다 상속성이 선호됩니다.


3
인터페이스는 상속과 관련이 없습니다.
DougM

1
@ DougM, 아마 나는 잘 말하지 않았지만, 우리가 동의한다고 확신합니다.
Kent A.

1

전용 속성을 가지고 인터페이스 해야 하기 때문에 피할 수 :

  • 의도를 난독 화합니다 : 데이터 컨테이너 만 필요합니다.
  • 그것은 상속을 장려합니다 : 누군가가 미래에 우려를 섞을 확률
  • 직렬화를 방지합니다

여기에 두 가지 관심사가 혼합되어 있습니다.

  • 데이터로 요약
  • 계약으로서의 요약

요약은 ID와 설명의 두 문자열로 구성됩니다. 이것은 평범한 데이터입니다.

public class Summary {
    private readonly string id;
    private readonly string description;
    public Summary(string id, string description) {
        this.id = id;
        this.description = description;
    }
    public string Id { get { return id; } }
    public string Description { get { return description; } }
}

계약을 정의하려는 요약을 정의 했으므로 다음을 수행하십시오.

public interface ISummarizableEntity {
    public Summary GenerateSummary();
}

게터에 지능을 사용하는 것은 반 패턴이며 피해야합니다. 대신 기능에 위치해야합니다. 구현 방식은 다음과 같습니다.

public partial class User : ISummarizableEntity {
    public Summary GenerateSummary() {
        var id = UserID.ToString();
        var description = String.Format("{0} {1} is from {2} and is {3} years old", FirstName, LastName, Country, Age);
        return new Summary(id,description);
    }
}

public partial class Product : ISummarizableEntity {
    public Summary GenerateSummary() {
        var id = ProductID.ToString();
        var description = String.Format("{0} weighs {1}{2} and belongs in the {3} department", ProductName, WeightValue, WeightUnit, Department);
        return new Summary(id,description);
    }
}

"속성 만 가지고있는 인터페이스는 피해야한다"고 동의하지 않습니다. 왜 그렇게 생각하는지 추론하십시오.
Euphoric

내가 약간의 세부 사항을 추가했습니다
vanna
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.