구현 (HashMap) 대신 인터페이스 (예 : Map)를 사용하여 Java 객체를 정의해야하는 이유


17

대부분의 Java 코드에서 사람들은 다음과 같이 Java 객체를 선언합니다.

Map<String, String> hashMap = new HashMap<>();
List<String> list = new ArrayList<>();

대신에:

HashMap<String, String> hashMap = new HashMap<>();
ArrayList<String> list = new ArrayList<>();

실제로 사용될 구현이 아닌 인터페이스를 사용하여 Java 객체를 정의하는 것이 선호되는 이유는 무엇입니까?


답변:


26

그 이유는 이러한 인터페이스의 구현은 일반적으로 인터페이스를 처리 할 때 관련이 없기 때문에 호출자 HashMap에게 a 메소드 를 전달하도록 강요하면 본질적으로 어떤 구현을 사용해야 하는가입니다. 따라서 일반적으로 실제 구현이 아닌 인터페이스를 처리하고 대신 HashMap사용해야 할 때 사용하는 모든 메소드 서명을 변경해야 할 고통과 고통을 피해야합니다 LinkedHashMap.

구현이 관련 될 때 예외가 있다고 말해야합니다. 순서가 중요 할 때 맵이 필요한 경우 a TreeMap또는 a LinkedHashMap를 전달하거나 SortedMap특정 구현을 지정하지 않는 것이 좋습니다 . 이것은 호출자가 반드시 특정 유형의 Map 구현을 반드시 통과해야하며 순서 중요하다는 것을 암시합니다 . 즉, SortedMap정렬되지 않은 것을 무시 하고 전달할 수 있습니까? 그러나 물론 결과적으로 나쁜 일이 일어날 것으로 기대합니다.

그러나 모범 사례에 따르면 중요하지 않은 경우 특정 구현을 사용해서는 안됩니다. 이것은 일반적으로 사실입니다. 상속을 최대한 활용하기 위해을 처리 Dog하고 Cat파생하는 Animal경우 일반적으로 Dog또는 특정 메소드를 사용하지 않아야합니다 Cat. 오히려 모든 메소드에 Dog있거나 메소드를 Cat대체해야 Animal하며 장기적으로 문제를 줄일 수 있습니다.


정렬 된 맵이 필요한 경우 매개 변수 유형은 SortedMap아닌 이어야합니다 TreeMap.
Cephalopod

@Arian SortedMap은 주문을 처리하는 여러 구현 중 하나입니다. 그것은 요점 외에입니다. TreeMap또한 키의 구현 Comparable또는 Comparator인터페이스 에 따라 항목을 주문합니다 .
Neil

아니요, SortedMap은 구현이 아니며 정확히 요점입니다. 키별로 정렬되는 맵의 인터페이스입니다.
Cephalopod

1
@Arian Ah 무슨 말인지 알겠습니다. 사실, 더 나은 SortedMap은 구현을 강제하지 않기 때문에 더 좋습니다. 적절하게 조정하겠습니다.
Neil

실제로,는 LinkedHashMap구현하지 않습니다 SortedMap. 의 유일한 하위 클래스 SortedMapConcurrentSkipListMapTreeMap입니다.
bcorso

10

Layman의 말에 따르면 :

전기 설비 제조업체가 케이블을 단순히 벗겨내는 대신 전기 플러그로 제품을 제작 한 것과 같은 이유로 집에는 케이블을 벗겨내는 대신 벽면 콘센트가 붙어 있습니다.

대신 표준 플러그를 사용하면 집안의 모든 호환 플러그에 동일한 장치를 연결할 수 있습니다.

벽면 콘센트의 관점에서 TV 세트 또는 스테레오 연결 여부는 중요하지 않습니다.

따라서 어플라이언스와 소켓이 더 유용합니다.

예를 들어 Map을 인수로 받아들이는 메소드를 예로 들어 보겠습니다.

이 메소드는 Map의 서브 클래스 인 경우 HashMap 또는 LinkedHashMap을 전달하는 것과 상관없이 작동합니다.

이것이 Liskov 대체 원칙 입니다.

제공 한 샘플 코드에서 나중에 어떤 이유로 든 해시의 구체적인 구현을 변경할 수 있으며 나머지 코드를 변경할 필요가 없습니다.

소프트웨어의 문제점은 벽돌이나 박격포를 낭비하지 않고 나중에 물건을 변경하기가 비교적 쉽기 때문에 사람들은 미리 생각할 가치가 없다고 생각합니다. 그러나 실제로는 소프트웨어 유지 관리가 매우 비싸다는 것을 보여주었습니다.


4

인터페이스 분리 원리 ( SOLID 의 'I') 를 따라야합니다. ) . 필요하지 않은 객체의 메소드에 따라 해당 객체를 사용하는 코드를 방지하여 코드의 결합이 덜되어 변경하기가 더 쉽습니다.

예를 들어 나중에 나중에 실제로 필요한 것이 LinkedHashMap있으면 다른 코드에 영향을주지 않고 안전하게 변경할 수 있습니다.

그러나 객체를 매개 변수로 사용할 수있는 코드를 인위적으로 제한하기 때문에 절충안이 있습니다. 말 함수 어딘가에있을 필요HashMap어떤 이유로. 를 반환하면 Map객체를 해당 함수에 전달할 수 없습니다. 미래에는 언젠가는보다 구체적인 클래스에있는 추가 기능이 필요하며 커플 링을 제한하고 공용 인터페이스를 최대한 작게 유지하려는 욕구의 균형을 맞춰야합니다.


3

변수를 인터페이스로 제한하면 해당 변수의 사용법이 사용되지 않습니다. HashMap 인터페이스에 존재하지 않을 수있는 특정 기능을 하지 않게되므로, 새로운 인스턴스도 구현하는 한, 나중에 다른 구현으로 문제없이 변경 될 수 있습니다. 상호 작용.

따라서 객체 인터페이스를 사용하려는 경우에는 항상 특정 구현이 아닌 인터페이스로 변수를 선언하는 것이 좋습니다. 인터페이스가있는 모든 유형의 객체에 적용됩니다. 당신이 종종 그것을 보는 이유는 많은 사람들이 이것을 습관으로 구축했기 때문입니다.

즉, 때때로 인터페이스 사용을 생략하는 것은 해롭지 않으며, 대부분의 사람들은 이 규칙을 항상 해치지 않고 실제로 해를 끼치 지 않습니다. 코드가 변경되어 향후 유지 관리 / 성장이 필요할 수 있다는 느낌이들 때 고수하는 것이 좋습니다. 의심스럽지 않은 코드를 해킹 할 때 수명이 길거나 중요도가 높은 것은 걱정할 필요가 없습니다. 또한이 규칙을 어기면 구현을 다른 것으로 변경하는 데 약간의 리팩토링이 필요할 수 있으므로 항상 따르지 않으면 크게 해치지 않지만 실제로 따르는 데 아무런 해가 없습니다. .

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