-
아이템20. 추상 클래스보다 인터페이스를 우선하라.Java/이펙티브 자바 2023. 8. 31. 11:51
핵심 정리 - 인터페이스의 장점
- 자바 8부터 인터페이스도 디폴트 메서드를 제공할 수 있다. (완벽 공략 3)
public interface TimeClient { void setTime(int hour, int minute, int second); void setDate(int day, int month, int year); void setDateAndTime(int day, int month, int year, int hour, int minute, int second); LocalDateTime getLocalDateTime(); static ZoneId getZonedId(String zoneString) { try { return ZoneId.of(zoneString); } catch (DateTimeException e) { System.err.println("Invalid time zone : " + zoneString + "; using default time zone instead"); return ZoneId.systemDefault(); } } default ZonedDateTime getZonedDateTime(String zoneString) { return ZonedDateTime.of(getLocalDateTime(), getZonedId(zoneString)); } }
ㆍ인스턴스의 필드를 사용하는 경우 default 메서드를 사용할 수 없다. - 추상 클래스를 사용해야 한다
- 기존 클래스도 손쉽게 새로운 인터페이스를 구현해 넣을 수 있다.
- 인터페이스는 믹스인(mixtin) 정의에 안성맞춤이다. (선택적인 기능 추가)
ㆍ부가적인 implements
- 계층구조가 없는 타입 프레임워크를 만들 수 있다.
public interface SingerSongwriter extends Singer, Songwriter { AutoClip strum(); void actSensitive(); }
- 래퍼 클래스와 함께 사용하면 인터페이스는 기능을 향상 시키는 안전하고 강력한 수단이 된다. (아이템 18)
- 구현이 명백한 것은 인터페이스의 디폴트 메서드를 사용해 프로그래머의 일감을 덜어 줄 수 있다.
핵심 정리 - 인터페이스와 추상 골격(skeletal) 클래스
- 인터페이스와 추상 클래스의 장점을 모두 취할 수 있다.
ㆍ인터페이스 - 디폴트 메서드 구현
ㆍ추상 골격 클래스 - 나머지 메서드 구현
ㆍ템플릿 메서드 패턴
- 다중 상속을 시뮬레이트할 수 있다.
public class MyCat extends AbstractCat implements Flyable { private MyFlayable myFlayable = new MyFlayable(); @Override protected String sound() { return "인싸 고양이 두 마리가 나가신다!"; } @Override protected String name() { return "유미"; } public static void main(String[] args) { MyCat myCat = new MyCat(); System.out.println(myCat.sound()); System.out.println(myCat.name()); myCat.fly(); } @Override public void fly() { this.myFlayable.fly(); } private class MyFlayable extends AbstractFlyable { // 다중 상속 @Override public void fly() { System.out.println("날아라."); } } }
- 골격 구현은 상속용 클래스이기 때문에 아이템 19를 따라야 한다.
완벽 공략
- p132, 템플릿 메서드 패턴
- p135, 디폴트 메서드는 equals, hashCode, toString 같은 Object 메서드를 재정의 할 수 없기 때문이다.
완벽 공략 - 템플릿 메서드 패턴
: 알고리즘 구조를 서브 클래스가 확장할 수 있도록 템플릿으로 제공하는 방법
- 추상 클래스는 템플릿을 제공하고 하위 클래스는 구체적인 알고리즘을 제공한다.
템플릿 메서드 패턴
public abstract class FileProcessor { private String path; public FileProcessor(String path) { this.path = path; } public final int process(BiFunction<Integer, Integer, Integer> operator) { try(BufferedReader reader = new BufferedReader(new FileReader(path))) { int result = 0; String line = null; while((line = reader.readLine()) != null) { result = getResult(result, Integer.parseInt(line)); // 템플릿 메서드 패턴 } return result; } catch (IOException e) { throw new IllegalArgumentException(path + "에 해당하는 파일이 없습니다.", e); } } protected abstract int getResult(int result, int number); }
public class Plus extends FileProcessor { public Plus(String path) { super(path); } @Override protected int getResult(int result, int number) { return result + number; } }
public static void main(String[] args) { FileProcessor fileProcessor = new Plus("number.txt"); System.out.println(fileProcessor.process()); }
템플릿 콜백 패턴
public class FileProcessor { private String path; public FileProcessor(String path) { this.path = path; } public final int process(BiFunction<Integer, Integer, Integer> operator) { try(BufferedReader reader = new BufferedReader(new FileReader(path))) { int result = 0; String line = null; while((line = reader.readLine()) != null) { result = operator.apply(result, Integer.parseInt(line)); // 템플릿 콜백 패턴 } return result; } catch (IOException e) { throw new IllegalArgumentException(path + "에 해당하는 파일이 없습니다.", e); } } }
public static void main(String[] args) { FileProcessor fileProcessor = new FileProcessor("number.txt"); System.out.println(fileProcessor.process(Integer::sum)); }
완벽 공략 - 디폴트 메서드와 Object 메서드
: 인터페이스의 디폴트 메서드로 Object 메서드를 재정의 할 수 없는 이유
// 틀린 예제 public interface MyInterface { default String toString() { return "myString"; } default int hashCode() { return 10; } default boolean equals(Object o) { return true; } }
- 디폴트 메서드 핵심 목적은 "인터페이스의 진화".
- 두가지 규칙만 유지한다.
ㆍ"클래스가 인터페이스를 이긴다."
public class MyClass extends Object implements MyInterface { } // 만약 MyInterface의 메서드를 사용한다면 위와 같은 법칙을 어기는 것이다.
ㆍ"더 구체적인 인터페이스가 이긴다."
- 토이 예제에나 어울리는 기능이다. 실용적이지 않다
- 불안정하다.
'Java > 이펙티브 자바' 카테고리의 다른 글
아이템 22 & 아이템 23 & 아이템 24 & 아이템 25 (0) 2023.09.07 아이템21. 인터페이스는 구현하는 쪽에서 생각해 설계하라. (0) 2023.09.05 아이템19. 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라. (0) 2023.08.30 아이템18. 상속보다는 컴포지션을 사용하라 (0) 2023.08.23 아이템17. 변경 가능성을 최소화 하라. (0) 2023.08.15