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


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.