인터페이스를 언제 반환해야 하며 언제 구체적인 클래스를 반환해야 합니까?

StackOverflow https://stackoverflow.com/questions/932452

  •  06-09-2019
  •  | 
  •  

문제

Java로 프로그래밍할 때 나는 거의 항상 습관적으로 다음과 같이 작성합니다.

public List<String> foo() {
    return new ArrayList<String>();
}

대부분의 경우 그것에 대해 생각조차 하지 않고 있습니다.이제 질문은 다음과 같습니다.내가해야합니까 언제나 인터페이스를 반환 유형으로 지정하시겠습니까?아니면 인터페이스의 실제 구현을 사용하는 것이 바람직합니까? 그렇다면 어떤 상황에서 사용됩니까?

인터페이스를 사용하면 많은 장점이 있다는 것은 분명합니다(그래서 인터페이스가 존재하는 것입니다).대부분의 경우 라이브러리 함수에서 어떤 구체적인 구현을 사용하는지는 중요하지 않습니다.하지만 어쩌면 그것이 중요한 경우가 있을 수도 있습니다.예를 들어, 내가 주로 목록에 있는 데이터에 무작위로 액세스한다는 것을 알고 있다면 LinkedList 나쁠 것입니다.하지만 내 라이브러리 함수가 인터페이스만 반환하는 경우에는 알 수 없습니다.안전을 위해 목록을 명시적으로 복사해야 할 수도 있습니다. ArrayList:

List bar = foo();
List myList = bar instanceof LinkedList ? new ArrayList(bar) : bar;

하지만 그건 정말 끔찍한 것 같고 내 동료들이 식당에서 나를 린칭할 수도 있습니다.그리고 당연히 그렇습니다.

여러분은 어떻게 생각하시나요?귀하의 지침은 무엇이며, 추상적인 솔루션을 지향하는 경우는 언제이며, 잠재적인 성능 향상을 위한 구현 세부 정보는 언제 공개합니까?

도움이 되었습니까?

해결책

예를 들어, 내가 목록의 데이터에 주로 무작위로 액세스 할 것이라는 것을 알고 있다면 Linkedlist는 나빠질 것입니다. 그러나 내 라이브러리 함수가 인터페이스 만 반환하면 단순히 모르겠습니다. 안전한쪽에 있으려면 목록을 Arraylist에 명시 적으로 복사해야 할 수도 있습니다.

다른 모든 사람들이 언급했듯이 라이브러리가 기능을 구현 한 방법에 대해 신경 쓰지 않아야하며 라이브러리의 커플 링 및 유지 관리 가능성을 증가시킵니다.

도서관 클라이언트로서 구현이 유스 케이스에 대해 잘못 수행되고 있음을 입증 할 수 있다면 담당자에게 연락하여 다음과 같은 최상의 경로에 대해 논의 할 수 있습니다 (이 사례에 대한 새로운 방법 또는 구현 변경). .

즉, 당신의 모범은 조기 최적화의 결과입니다.

메소드가 중요하거나 중요 할 수 있다면 문서의 구현 세부 사항을 언급 할 수 있습니다.

다른 팁

구현 세부 정보를 숨기려면 적절한 인터페이스를 반환하십시오. 고객은 객체를 구현하는 방법이 아니라 객체가 제공하는 것에 대해서만 관심을 가져야합니다. 개인 Arraylist로 시작하고 나중에 다른 내용 (예 : LinkedLisk, Skip List 등)이 더 적절하다는 것을 나중에 결정하면 인터페이스를 반환하는 경우 클라이언트에 영향을 미치지 않고 구현을 변경할 수 있습니다. 콘크리트 유형을 반환하는 순간 기회가 손실됩니다.

OO 프로그래밍에서는 가능한 한 데이터를 캡슐화하려고합니다. 가능한 한 높은 유형을 최대한 많이 숨기고 가능한 한 많이 숨기십시오.

이 맥락에서 나는 대답 할 것이다 의미있는 것을 반환하십시오. 리턴 값이 콘크리트 클래스가되는 것이 전혀 의미가 있습니까? AKA 예에서는 자신에게 물어보십시오. 누구든지 FOO의 반환 값에 대한 LinkedList 별 방법을 사용합니까?

  • 아니오 인 경우 더 높은 수준의 인터페이스를 사용하십시오. 훨씬 더 유연하고 백엔드를 변경할 수 있습니다.
  • 그렇다면 스스로에게 물어보십시오. 하이 레벨 인터페이스를 반환하기 위해 내 코드를 리팩토링 할 수 없습니까? :)

코드가 더 추상적 일수록 백엔드를 변경할 때 필요한 변경 사항이 적습니다. 그렇게 간단합니다.

반면에, 당신이 콘크리트 클래스에 반환 값을 캐스팅하게된다면, 그것은 아마도 당신이 아마도 콘크리트 클래스를 반환해야한다는 강한 신호입니다. 사용자/팀원은 다소 암시 적 계약에 대해 알 필요가 없습니다. 구체적인 방법을 사용해야하는 경우 명확하게 콘크리트 클래스를 반환하십시오.

간단히 말해서 : 코드 요약, 하지만 명시 적으로 :)

CS 인용문의 림으로 그것을 정당화 할 수 없다면 (나는 자기 가르쳤다), 나는 항상 "수업을 수락하고, 가장 파생 된 사람들을 가장 많이 반환하고, 가장 파생 된 것을 반환한다"라는 만트라를 항상 갔다. 몇 년.

인터페이스 대 콘크리트 리턴 측면에서 의존성을 줄이고/또는 해체하려는 경우 인터페이스를 반환하는 것이 일반적으로 더 유용하다는 것입니다. 그러나 콘크리트 클래스가 구현되는 경우 해당 인터페이스보다 일반적으로 방법의 발신자에게 콘크리트 클래스를 다시 얻는 것이 (즉, "가장 파생 된")를 반환 된 객체의 기능의 하위 집합으로 제한하는 대신 (즉 필요 그들을 제한합니다. 그런 다음 다시 인터페이스의 적용 범위를 늘릴 수도 있습니다. 이와 같은 불필요한 제한은 무의미한 클래스 봉인과 비교됩니다. 당신은 결코 알지 못합니다. 그 만트라의 이전 부분 (다른 독자들을 위해)에 대해 조금 이야기하기 위해, 가장 파생 된 것을 수용하면 방법의 발신자에게 최대의 유연성을 제공합니다.

-이신

일반적으로 API와 같은 공개 인터페이스의 경우 인터페이스(예: List) 구체적인 구현(예: ArrayList) 더 좋을 것 같아요.

의 사용 ArrayList 또는 LinkedList 해당 라이브러리의 가장 일반적인 사용 사례에 대해 고려해야 하는 라이브러리의 구현 세부 사항입니다.그리고 물론 내부적으로는 private 전달 방법 LinkedList처리를 더 쉽게 만드는 기능을 제공한다면 이것이 반드시 나쁜 것은 아닙니다.

다른 클래스가 있다고 믿을 만한 타당한 이유가 없는 한, 구현에 구체적인 클래스를 사용해서는 안 될 이유가 없습니다. List 클래스는 나중에 사용됩니다.그러나 공개 부분이 잘 설계되어 있는 한 구현 세부 사항을 변경하는 것은 그리 어렵지 않습니다.

라이브러리 자체는 소비자에게 블랙박스가 되어야 하므로 내부적으로 무슨 일이 일어나고 있는지 걱정할 필요가 없습니다.이는 또한 라이브러리가 의도한 방식으로 사용되도록 설계되어야 함을 의미합니다.

원칙적으로, 나는 도서관의 개인적이고 내부 작업에있는 경우에만 내부 구현을 전달합니다. 공개되어 있고 모듈 외부에서 호출 될 가능성이있는 모든 것에 대해 인터페이스와 공장 패턴을 사용합니다.

이러한 방식으로 인터페이스를 사용하는 것은 재사용 가능한 코드를 작성하는 매우 신뢰할 수있는 방법으로 입증되었습니다.

주요 질문은 이미 답변되었으며 항상 인터페이스를 사용해야합니다. 그러나 나는 그냥 댓글을 달고 싶다

인터페이스를 사용하는 것은 많은 장점이 있다는 것이 분명합니다 (그래서 그것이 존재하는 이유). 대부분의 경우 라이브러리 기능에서 어떤 구체적인 구현이 사용되는지는 중요하지 않습니다. 그러나 그것이 중요한 경우가있을 수 있습니다. 예를 들어, 내가 목록의 데이터에 주로 무작위로 액세스 할 것이라는 것을 알고 있다면 Linkedlist는 나빠질 것입니다. 그러나 내 라이브러리 함수가 인터페이스 만 반환하면 단순히 모르겠습니다. 안전한쪽에 있으려면 목록을 Arraylist에 명시 적으로 복사해야 할 수도 있습니다.

당신이 알고있는 데이터 구조를 반환하는 경우, 무작위 액세스 성능이 좋지 않은 경우 (O (n)과 일반적으로 많은 데이터가 있습니다. 라이브러리를 사용하는 사람이라면 반복 가능성과 같이 목록 대신 지정 해야하는 다른 인터페이스가 있습니다. 순차적 액세스 만 사용할 수 있음을 완전히 알고 있습니다.

반환 할 올바른 유형을 선택하는 것은 인터페이스 대 콘크리트 구현에 관한 것이 아니라 올바른 인터페이스를 선택하는 것입니다.

API 메소드가 인터페이스 또는 콘크리트 클래스를 반환하는지 여부는 중요하지 않습니다. 여기의 모든 사람이 말하는 내용에도 불구하고 코드가 작성되면 구현 클래스를 거의 변경하지 않습니다.

훨씬 더 중요한 것 : 항상 방법에 최소 스코프 인터페이스를 사용하십시오. 매개 변수! 이렇게하면 고객은 최대의 자유를 가지고 있으며 코드가 모르는 클래스를 사용할 수 있습니다.

API 메소드가 돌아올 때 ArrayList, 나는 그것에 대해 전혀 자격이 없지만, 그것이 필요할 때 ArrayList (또는 모두 공통적으로, Vector) 매개 변수, 나는 프로그래머를 사냥하고 그를 아프게하는 것을 고려합니다. Arrays.asList(), Collections.singletonList() 또는 Collections.EMPTY_LIST.

동의하지 않아서 죄송하지만 기본 규칙은 다음과 같습니다.

  • 을 위한 입력 인수는 가장 많이 사용됩니다 일반적인.
  • 을 위한 산출 가치, 가장 특정한.

따라서이 경우 구현을 다음과 같이 선언하려고합니다.

public ArrayList<String> foo() {
  return new ArrayList<String>();
}

이론적 해석: 입력 케이스는 이미 모든 사람이 알려지고 설명합니다. 인터페이스, 기간을 사용하십시오. 그러나 출력 케이스는 반 직관적으로 보일 수 있습니다. 클라이언트가받는 내용에 대한 정보를 가장 많이 갖기를 원하기 때문에 구현을 반환하려고합니다. 이 경우 더 많은 지식은 더 많은 힘입니다.

예 1 : 클라이언트는 5 번째 요소를 얻기를 원합니다.

  • 반환 컬렉션 : 5 번째 요소 대 반환 목록까지 반복해야합니다.
  • 반환 목록 : list.get(4)

예 2 : 클라이언트는 5 번째 요소를 제거하려고합니다.

  • 반환 목록 : 지정된 요소없이 새 목록을 작성해야합니다 (list.remove() 선택 사항).
  • 반환 배열리스트 : arrayList.remove(4)

따라서 인터페이스를 사용하는 것은 재사용 성을 촉진하고, 커플 링을 줄이고, 유지 관리를 향상시키고, 사람들을 행복하게 만드는 것은 큰 사실입니다. 입력.

다시, 규칙은 다음과 같이 언급 될 수 있습니다.

  • 당신이 제공하는 것을 유연하게하십시오.
  • 당신이 제공하는 것에 유익한 정보를 얻으십시오.

다음 번에는 구현을 반환하십시오.

인터페이스를 사용하여 실제 구현에서 멀리 떨어져 있습니다. 인터페이스는 기본적으로 구현이 할 수있는 일에 대한 청사진입니다.

인터페이스는 좋은 디자인입니다. 구현이 여전히 인터페이스가하는 일을 수행하는 한 소비자가 직접 영향을받는 것을 두려워하지 않고 구현 세부 사항을 변경할 수 있기 때문에 좋은 디자인입니다.

인터페이스로 작업하려면 다음과 같이 인스턴스화합니다.

IParser parser = new Parser();

이제 IPARSER가 귀하의 인터페이스가 될 것이며 Parser는 귀하의 구현이 될 것입니다. 이제 위의 파서 객체와 함께 작업하면 인터페이스 (IPARSER)에 대해 작업하면 구현 (Parser)에 대해 작동합니다.

즉, 파서의 내부 작업을 원하는만큼 변경할 수 있으며 IPARSER 파서 인터페이스에 대해 작동하는 코드에 영향을 미치지 않습니다.

콘크리트 클래스의 기능이 필요하지 않은 경우 일반적으로 모든 경우에 인터페이스를 사용하십시오. 목록의 경우 Java가 추가했습니다 무작위 대응 마커 클래스는 주로 알고리즘이 get (i)가 일정한 시간인지 아닌지 알아야하는 공동 사례를 구별합니다.

코드 사용의 경우 Michael 위의 Michael은 방법 매개 변수에서 가능한 한 일반적인 것이 종종 더 중요하다는 것이 옳습니다. 이것은 그러한 방법을 테스트 할 때 특히 그렇습니다.

인터페이스를 반환 할 때 코드를 통해 스며 든다는 것을 찾거나 찾았습니다. 예를 들어 메소드 A와 귀하의 인터페이스를 반환합니다. 가지다 그런 다음 인터페이스를 메소드 B로 전달합니다.

당신이하는 일은 제한된 방식이지만 계약에 따라 프로그래밍하는 것입니다.

이를 통해 커버에서 구현을 변경할 수있는 엄청난 범위를 제공합니다 (이러한 새로운 개체가 기존 계약/예상 동작을 충족시킨 경우).

이 모든 것이 주어지면 구현을 선택하는 데있어 이점과 행동을 대체 할 수있는 방법 (예 : 조롱 사용)을 대체 할 수있는 방법이 있습니다. 당신이 짐작하지 않은 경우, 나는 이것을 선호하고 가능한 한 인터페이스를 줄이거 나 소개하려고 노력합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top