분류에만 인터페이스를 사용하는 것은 나쁜 습관입니까?


12

예를 들면 다음과 같습니다.

내가 수업을 말한다 A, B, C. 나는 두 개의 인터페이스를 가지고, 그들에게 전화 할 수 있습니다 IAnimalIDog. IDog에서 상속 IAnimal합니다. A하고 B있는 IDog반면, S C아니지만, 그것은이다 IAnimal.

중요한 부분은 IDog추가 기능 을 제공하지 않는다는 것입니다. 단지 허용하는 데 사용됩니다 A하고 B있지만 C, 특정 방법에 인수로 전달 될 수 있습니다.

이것은 나쁜 습관입니까?


8
IAnimal하고 IDog있는 끔찍한 동어 반복의 이름!

5
@JarrodRoberson은 동의하는 경향이 있지만 .Net 세계에서 일하는 경우 일종의 문제에 봉착합니다 (또는 다르게 수행하면 기존의 규칙에 위배됩니다).
Daniel B

2
@JarrodRoberson 이럴 MyProject.Data.IAnimalMyProject.Data.Animal보다 나은 MyProject.Data.Interfaces.AnimalMyProject.Data.Implementations.Animal
마이크 Koder

1
요점은 반복적 인 접두사 또는 네임 스페이스 중 어느 하나이든, 또는 그것이 타우 톨 로지이며 DRY를 위반 하는 경우 Interface또는 걱정하지 않아도 될 이유가 없다는 것 Implementation입니다. Dog당신이 신경 써야 할 전부입니다. PitBull extends Dog구현 중복이 필요하지 않습니다.이 단어 extends는 내가 알아야 할 모든 것을 말해줍니다. 원래 의견에 게시 한 링크를 읽으십시오.

1
@Jarrod : 나에게 불평을 그만두십시오. .NET 개발자 팀에 불평하십시오. 내가 표준을 어기면 동료 개발자들은 내 용기를 싫어할 것입니다.
Kendall Frey

답변:


13

마커 인터페이스라는 동일한 인터페이스에서 상속 된 다른 인터페이스와 멤버가 없거나 정확히 동일한 멤버가있는 인터페이스이며이를 마커로 사용하고 있습니다.

사용하는 언어가 지원하는 경우 나쁜 습관은 아니지만 인터페이스를 속성 (주석)으로 대체 할 수 있습니다.

오차드 프로젝트 에서 "마커 인터페이스"패턴을 많이 사용했기 때문에 이것이 나쁜 습관이 아니라고 자신있게 말할 수 있습니다.

다음은 오차드 프로젝트의 샘플 입니다.

public interface ISingletonDependency : IDependency {}

/// <summary>
/// Base interface for services that may *only* be instantiated in a unit of work.
/// This interface is used to guarantee they are not accidentally referenced by a singleton dependency.
/// </summary>
public interface IUnitOfWorkDependency : IDependency {}

/// <summary>
/// Base interface for services that are instantiated per usage.
/// </summary>
public interface ITransientDependency : IDependency {}

마커 인터페이스를 참조하십시오 .


속성 / 주석이 컴파일 타임 확인 (C #을 참조 언어로 사용)을 지원합니까? 객체에 속성이 없으면 예외를 던질 수 있지만 인터페이스 패턴은 컴파일 타임에 오류를 잡습니다.
Kendall Frey

Marker Interface를 사용하는 경우 컴파일 검사 이점이 전혀 없습니다. 기본적으로 인터페이스를 통한 유형 검사를 수행하고 있습니다.
Freshblood 2016 년

혼란 스러워요. 이 '마커 인터페이스'패턴은을 C기대하는 메소드에 a 를 전달할 수 없다는 점에서 컴파일 타임 검사를 제공 합니다 IDog.
Kendall Frey

이 패턴을 사용하는 경우 리플렉션 작업을 수행하는 것입니다. 유형 검사를 수행하는 것은 동적 분석 또는 정적 분석입니다. 유스 케이스에 문제가 있다고 확신하지만 어떻게 사용하는지 보지 못했습니다.
Freshblood 2016 년

Telastyn의 답변에 대한 의견에서 한 것처럼 설명하겠습니다. 예를 들어 s Kennel목록을 저장 하는 클래스가 있습니다 IDog.
Kendall Frey

4

예, 거의 모든 언어에서 나쁜 습관입니다.

데이터를 인코딩 할 유형이 없습니다. 데이터가 이동해야하는 위치로 이동하고 작동해야하는 것처럼 작동 함을 증명하는 데 도움이됩니다. 하위 유형을 지정하는 유일한 이유는 다형성 동작이 변경되는 경우입니다 (항상 그런 것은 아님).

타이핑이 없기 때문에 IDog가 할 수있는 것은 내포되어 있습니다. 한 프로그래머는 한 가지를 생각하고 다른 프로그래머는 다른 것을 생각하고 사물을 분해합니다. 또는 더 세밀한 제어가 필요할수록 그 수치가 증가합니다.

[편집 : 설명]

내 말은 당신이하고있는 것입니다 몇 가지 인터페이스를 기반으로 논리를. 왜 어떤 방법은 개나 다른 동물에게만 작용할 수 있습니까? 차이를 제공하는 실제 구성원이 없기 때문에 이러한 차이는 묵시적 계약입니다. 시스템에 실제 데이터 가 없습니다 . 유일한 차이점은 인터페이스 (따라서 '타이핑 없음'주석)와 그 의미 는 프로그래머마다 다릅니다. [/편집하다]

어떤 언어는 그렇게 나쁘지는 않지만 특성화에 중점을 두는 경향이있는 특성 메커니즘을 제공합니다. 나는 그들에 대한 경험이 거의 없으므로 모범 사례와 이야기 할 수 없습니다. C ++ / Java / C #에서는 좋지 않습니다.


나는 당신의 중간 두 단락으로 혼란스러워합니다. '서브 타입'은 무엇을 의미합니까? 구현이 아닌 계약 인 인터페이스를 사용하고 있으며 귀하의 의견이 어떻게 적용되는지 잘 모르겠습니다. '타자 없음'이란 무엇입니까? '암시 적'이란 무엇을 의미합니까? IDog는 IAnimal이 할 수있는 모든 것을 할 수 있지만 더 많은 것을 할 수 있다고 보장하지는 않습니다.
Kendall Frey

설명 주셔서 감사합니다. 필자의 경우에는 인터페이스를 정확하게 다르게 사용하지 않습니다. s Kennel목록을 저장하는 클래스가 있다고 말하면 가장 잘 설명 될 수 있습니다 IDog.
Kendall Frey 2016 년

@ KendallFrey : 인터페이스 (나쁜)에서 캐스트하거나 잘못된 추상화 냄새가 나는 인공적인 구별을 만들고 있습니다.
Telastyn 2016 년

2
@Telastyn-인터페이스와 같은 목적은 메타 데이터를 제공하는 것입니다
Freshblood

1
@ Telastyn : 그렇다면 컴파일 타임 검사에 속성이 어떻게 적용됩니까? C #에서 AFAIK는 런타임에만 특성을 사용할 수 있습니다.
Kendall Frey

2

나는 C #을 잘 알고 있기 때문에 일반적으로 OO 프로그래밍에 대해서는 이것을 말할 수 없지만 C # 예제로서 클래스를 분류 해야하는 경우 명백한 옵션은 인터페이스, 열거 속성 또는 사용자 정의 속성입니다. 일반적으로 다른 사람들의 생각에 상관없이 인터페이스를 선택합니다.

if(animal is IDog)
{
}
if(animal.Type == AnimalType.Dog)
{
}
if(animal.GetType().GetCustomAttributes(typeof(DogAttribute), false).Any())
{
}


var dogs1 = animals.OfType<IDog>();
var dogs2 = animals.Where(a => a.Type == AnimalType.Dog);
var dogs3 = animals.Where(a => a.GetType().GetCustomAttributes(typeof(DogAttribute), false).Any());


var dogsFromDb1 = session.Query<IDog>();
var dogsFromDb2 = session.Query<Animal>().Where(a => a.Type == AnimalType.Dog);
var dogsFromDb3 = session.Query<Animal>().Where(a => a.GetType().GetCustomAttributes(typeof(DogAttribute),false).Any());


public void DoSomething(IDog dog)
{
}
public void DoSomething(Animal animal)
{
    if(animal.Type != AnimalType.Dog)
    {
        throw new ArgumentException("This method should be used for dogs only.");
    }
}
public void DoSomething(Animal animal)
{
    if(!animal.GetType().GetCustomAttributes(typeof(DogAttribute), false).Any())
    {
        throw new ArgumentException("This method should be used for dogs only.");
    }
}

코드의 마지막 섹션은 주로 내가 사용하는 것입니다. 인터페이스 버전이 훨씬 짧아지고 컴파일 타임이 확인되는 것을 알 수 있습니다.
Kendall Frey 2016 년

나는 비슷한 사용 사례를 가지고 있지만 대부분의 .net 개발자는 그것에 대해 강력히 권고하지만 속성을 사용하지 않을 것입니다.
GorillaApe

-1

후자의 인터페이스의 모든 구현이 전자의 일부 구현이 유용하지 않은 작업 을 유용하게 수행 할 수있을 것으로 예상되는 경우, 새 멤버를 추가하지 않고 다른 인터페이스를 상속하는 인터페이스를 갖는 것은 아무런 문제 가 없습니다. 실제로 IMHO가 .net Framework와 같은 것들에서 더 많이 사용되어야하는 좋은 패턴입니다. 특히 더 파생 된 인터페이스에 의해 암시 된 제약 조건을 클래스가 자연스럽게 충족시키는 구현자는 더 파생 된 인터페이스를 구현함으로써 간단히 나타낼 수 있기 때문에 멤버 구현 코드 또는 선언을 변경할 필요가 없습니다.

예를 들어 인터페이스가 있다고 가정합니다.

IMaybeMutableFoo 인터페이스
  Bar Thing {get; set;} // 그리고 다른 속성들
  부울 IsMutable;
  IImmutableFoo AsImmutable ();
}
인터페이스 IImmutableFoo : IMaybeMutableFoo {};

구현은 IImmutableFoo.AsImmutable()스스로를 반환 할 것으로 예상됩니다. 변경 가능한 클래스 구현 IMaybeMutableFoo.AsImmutable()은 데이터의 스냅 샷을 포함하는 새로운 불변의 새로운 객체를 반환 할 것으로 예상됩니다. 에 보유 된 데이터의 스냅 샷을 저장하려는 루틴 IMaybeMutableFoo은 과부하를 제공 할 수 있습니다.

공공 무효 StoreData (IImmutableFoo ThingToStore)
{
  // ThingToStore가 불변 인 것으로 알려져 있기 때문에 참조를 저장하면 충분합니다.
}
공공 무효 StoreData (IMaybeMutableFoo ThingToStore)
{
  StoreData (ThingToStore.AsImmutable ()); //보다 구체적인 과부하를 호출
}

컴파일러가 저장할 것이라는 것을 모르는 경우을 IImmutableFoo호출 AsImmutable()합니다. 항목이 이미 변경 불가능한 경우 함수가 빠르게 리턴되어야하지만 인터페이스를 통한 함수 호출에는 여전히 시간이 걸립니다. 컴파일러가 항목이 이미임을 알고 있으면 IImmutableFoo불필요한 함수 호출을 건너 뛸 수 있습니다.


Downvoter : 의견이 있으십니까? 새로운 것을 추가하지 않고 인터페이스를 상속받는 것은 어리석은 일이지만, 그것이 좋은 (그리고 IMHO가 사용하지 않는) 기술이 될 때가 없다는 것을 의미하지는 않습니다.
supercat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.