인터페이스를 사용하는 이유와 일반적으로 제한된 유형


15

일반 형식 매개 변수 (클래스 템플릿 및 매개 변수 다형성이라고도 함)를 지원하는 개체 지향 언어에서는 물론 각 이름에 다른 의미가 있지만 형식 매개 변수에 형식 제약 조건을 지정하여 내림차순으로 지정할 수있는 경우가 종종 있습니다 다른 유형에서. 예를 들어 다음은 C #의 구문입니다.

//for classes:
class ExampleClass<T> where T : I1 {

}
//for methods:
S ExampleMethod<S>(S value) where S : I2 {
        ...
}

해당 인터페이스에 의해 제한되는 유형보다 실제 인터페이스 유형을 사용해야하는 이유는 무엇입니까? 예를 들어, 메소드 서명을 작성하는 이유는 무엇 I2 ExampleMethod(I2 value)입니까?


4
클래스 템플릿 (C ++)은 완전히 제네릭과 완전히 다르고 훨씬 강력한 것입니다. 제네릭을 가진 언어가 템플릿 구문을 빌려 왔지만.
— 중복 제거기

인터페이스 메서드는 간접 호출이지만 형식 메서드는 직접 호출이 될 수 있습니다. 따라서 후자는 전자보다 빠를 수 있으며 ref값 유형 매개 변수 의 경우 실제로 값 유형을 수정할 수 있습니다.
— user541686

@ 중복 제거기 : 제네릭이 템플릿보다 오래되었다는 것을 고려할 때 제네릭이 템플릿, 구문 또는 다른 방법으로 템플릿에서 아무것도 빌릴 수 없었습니다.
— Jörg W Mittag

3
@ JörgWMittag : "제네릭을 지원하는 객체 지향 언어"에 의해 중복 제거기는 "ML 및 Ada"가 아니라 "Java 및 C #"을 이해했을 것입니다. 그렇다면 C ++에서 제네릭 또는 파라 메트릭 다형성을 갖는 모든 언어가있는 것은 아니지만 C ++이 전자에 미치는 영향은 분명 합니다.
— Steve Jessop

2
@SteveJessop : ML, Ada, Eiffel, Haskell은 C ++ 템플릿보다 앞서고 Scala, F #, OCaml이 나 왔으며 C ++의 구문을 공유하는 템플릿은 없습니다. 흥미롭게도 C ++, 특히 템플릿에서 많이 빌린 D조차도 C ++의 구문을 공유하지 않습니다. "Java와 C #"은 "제네릭이있는 언어"에 대한 다소 좁은 견해라고 생각합니다.
— Jörg W Mittag

답변:


21

파라 메트릭 버전을 사용하면

  1. 기능 사용자에게 자세한 정보
  2. 작성할 수있는 프로그램 수를 제한합니다 (무료 버그 검사)

임의의 예로서, 2 차 방정식의 근을 계산하는 방법이 있다고 가정합니다.

int solve(int a, int b, int c) {
  // My 7th grade math teacher is laughing somewhere
}

그리고 당신은 그것 이외의 것들과 같은 다른 종류의 숫자에서 작동하기를 원합니다 int. 당신은 같은 것을 쓸 수 있습니다

Num solve(Num a, Num b, Num c){
  ...
}

문제는 이것이 원하는 것을 말하지 않는다는 것입니다. 그것은 말한다

같은 방식으로 숫자가 아닌 3 가지를 알려 주면 일종의 숫자를 다시 알려 드리겠습니다.

우리는 같은 일을 할 수없는 int sol = solve(a, b, c)경우 a, b그리고 c있습니다 int우리는 방법이를 반환 위하여려고하고 있다는 것을 모르기 때문에들 int결국! 우리가 해결책을 더 큰 표현으로 사용하고 싶다면 다운 캐스팅과기도로 어색한 춤으로 이어집니다.

함수 내에서 누군가 플로트, bigint 및 degree를 우리에게 건네 줄 수 있으며 우리는 그것들을 더하고 곱해야합니다. 우리는이 3 가지 클래스 사이의 연산이 횡설수설이기 때문에 이것을 정적으로 거부하고 싶습니다. 학위는 mod 360이므로 a.plus(b) = b.plus(a)유사한 과실이 발생 하지 않습니다 .

서브 타이핑과 함께 파라 메트릭 다형성을 사용하면 타입이 실제로 의미하는 바를 나타 내기 때문에이 모든 것을 배제 할 수 있습니다

<T : Num> T solve(T a, T b, T c)

또는 "숫자 인 타입을 주면, 그 계수로 방정식을 풀 수 있습니다".

이것은 다른 많은 장소에서도 나타납니다. 예제의 또 다른 좋은 소스는 기능을하는 추상적 인 용기, 알라의 일종 끝났다 reverse, sort, map, 등


8
요약하면 일반 버전은 세 입력 (및 출력)이 모두 같은 유형 의 숫자 가되도록 합니다 .
— MathematicalOrchid

그러나 문제의 유형을 제어하지 않으면 인터페이스가 추가되지 않습니다. 최대한의 일반성을 위해서는 인수 유형 (예 :)으로 매개 변수화 된 인터페이스를 Num<int>추가 인수 로 받아 들여야합니다 . 위임을 통해 언제든지 모든 유형의 인터페이스를 구현할 수 있습니다. 인터페이스를 명시 적으로 전달해야하기 때문에 사용하기가 훨씬 지루한 것을 제외하고는 본질적으로 Haskell의 유형 클래스입니다.
— Doval

16

해당 인터페이스에 의해 제한되는 유형보다 실제 인터페이스 유형을 사용해야하는 이유는 무엇입니까?

그것이 당신이 필요로하는 것이기 때문에 ...

IFoo Fn(IFoo x);
T Fn<T>(T x) where T: IFoo;

두 개의 다른 서명이 있습니다. 첫 번째는 인터페이스를 구현하는 모든 유형을 사용하며 반환 값이 인터페이스를 만족한다는 것만 보장합니다.

두 번째는 인터페이스를 구현하는 모든 유형을 취하고 덜 제한적인 인터페이스를 만족시키는 것이 아니라 적어도 해당 유형을 다시 반환하도록 보장합니다.

때로는 더 약한 보증을 원합니다. 때때로 당신은 더 강한 것을 원합니다.


더 약한 보증 버전을 사용하는 방법에 대한 예를 들어 줄 수 있습니까?
— GregRos

4
@GregRos-예를 들어, 내가 작성한 파서 코드에서. 나는 기능이있어 Or이 소요 Parser오브젝트 (추상 기본 클래스를하지만 원칙은 유지) 반환 새로운 Parser(그러나 다른 유형). 최종 사용자는 콘크리트 유형이 무엇인지 알거나 신경 쓰지 않아야합니다.
— Telastyn

C #에서는 전달 된 것과 다른 T를 반환하는 것이 새로운 제약없이 거의 불가능합니다 (반사 통증 없음).
— NtscCobalt

1
@NtscCobalt : 파라 메트릭 및 인터페이스 일반 프로그래밍을 결합 할 때 더 유용합니다. 예를 들어 LINQ가 항상하는 IEnumerable<T>일 (을 받아들이고 IEnumerable<T>실제로 다른 것을 반환 함 OrderedEnumerable<T>)
— Ben Voigt

2

메서드 매개 변수에 제약이있는 제네릭을 사용하면 메서드가 전달 된 항목의 반환 형식을 기반으로 반환 형식을 매우 높일 수 있습니다. .NET에서는 추가 이점도있을 수 있습니다. 그들 중 :

  1. 제약 된 제네릭을 a ref또는 out매개 변수 로 받아들이는 방법에는 제약 조건 을 만족하는 변수가 전달 될 수 있습니다. 대조적으로, 인터페이스 유형 매개 변수를 갖는 비 제네릭 방법은 정확한 인터페이스 유형의 변수를 허용하는 것으로 제한됩니다.

  2. 제네릭 형식 매개 변수 T가있는 메서드는 T의 제네릭 컬렉션을 허용 할 수 있습니다.를 수락하는 메서드는을 수락 IList<T> where T:IAnimal할 수 List<SiameseCat>있지만 원하는 메서드 는을 수락 IList<Animal>할 수 없습니다.

  3. 제약 조건은 때때로 제네릭 형식으로 인터페이스를 지정할 수 있습니다 (예 :) where T:IComparable<T>.

  4. 인터페이스를 구현하는 구조는 제한된 일반 매개 변수를 허용하는 메소드에 전달 될 때 값 유형으로 유지 될 수 있지만 인터페이스 유형으로 전달 될 때 상자로 묶어야합니다. 속도에 큰 영향을 줄 수 있습니다.

  5. 일반 매개 변수에는 여러 제약 조건이있을 수 있지만 "IFoo 및 IBar를 모두 구현하는 일부 형식"의 매개 변수를 지정하는 다른 방법은 없습니다. 유형의 매개 변수를받은 코드 IFoo는 문제가있는 인스턴스가 모든 제약 조건을 충족하더라도 이중 구속 된 제네릭을 기대하는 그러한 방법으로 전달하기가 매우 어려울 수 있기 때문에 때로는 양날의 칼 일 수 있습니다.

특정 상황에서 제네릭을 사용하는 것의 이점이 없다면 인터페이스 유형의 매개 변수를 수락하십시오. 제네릭을 사용하면 형식 시스템과 JITter가 추가 작업을 수행해야하므로 아무런 이점이 없다면 그렇게하지 않아야합니다. 반면에, 위의 장점 중 하나 이상이 적용되는 것이 매우 일반적입니다.

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