tonykang22 / study

0 stars 0 forks source link

[이펙티브 자바] 아이템 20. 추상 클래스보다 인터페이스를 우선하라. #135

Open callmeaxxe opened 1 year ago

callmeaxxe commented 1 year ago

아이템 20. 추상 클래스보다 인터페이스를 우선하라.

핵심 정리: 인터페이스의 장점

보통 인터페이스는 타입을 정의할 때, 추상 클래스는 인터페이스의 기능을 일부 제공할 때 사용한다 추상 클래스를 상속받는 형식으로 사용하기보단, 인터페이스 구현의 방식을 우선 고려하라는 것

인터페이스 - default method

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();
        }
    }

    // interface default method
    default ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZonedId(zoneString));
    }

}

인터페이스 - 믹스인(mixtin)

public class SimpleTimeClient implements TimeClient, AutoCloseable {
    ...
}

인터페이스 - 계층구조가 없는 타입 프레임워크

인터페이스 - 래퍼 클래스와 함께 사용할 때

callmeaxxe commented 1 year ago

핵심 정리: 인터페이스와 추상 골격(skeletal) 클래스

추상 클래스 - 장점

// 코드 20-1 골격 구현을 사용해 완성한 구체 클래스 (133쪽)
public class IntArrays {
    static List<Integer> intArrayAsList(int[] a) {
        Objects.requireNonNull(a);

        // 다이아몬드 연산자를 이렇게 사용하는 건 자바 9부터 가능하다.
        // 더 낮은 버전을 사용한다면 <Integer>로 수정하자.
        return new AbstractList<>() {
            @Override public Integer get(int i) {
                return a[i];  // 오토박싱(아이템 6)
            }

            @Override public Integer set(int i, Integer val) {
                int oldVal = a[i];
                a[i] = val;     // 오토언박싱
                return oldVal;  // 오토박싱
            }

            @Override public int size() {
                return a.length;
            }
        };
    }

    public static void main(String[] args) {
        int[] a = new int[10];
        for (int i = 0; i < a.length; i++)
            a[i] = i;

        List<Integer> list = intArrayAsList(a);
        Collections.shuffle(list);
        System.out.println(list);
    }
}

추상 클래스 - 다중 상속 시뮬레이트

public class MyCat extends AbstractCat implements Flyable {

    private MyFlyable myFlyable = new MyFlyable();

    @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.myFlyable.fly();
    }

    private class MyFlyable extends AbstractFlyable {
        @Override
        public void fly() {
            System.out.println("날아라.");
        }
    }
}
callmeaxxe commented 1 year ago

완벽 공략

완벽 공략 36. 템플릿 메서드 패턴

알고리듬 구조를 서브 클래스가 확장할 수 있도록 템플릿으로 제공하는 방법.

템플릿 메서드 패턴 - 예제

public abstract class FileProcessor {

    private String path;

    public FileProcessor(String path) {
        this.path = path;
    }

    public final int process() {
        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 Client {

    public static void main(String[] args) {
        FileProcessor fileProcessor = new Plus("number.txt");
        System.out.println(fileProcessor.process());
    }

    public static class Plus extends FileProcessor {
        public Plus(String path) {
            super(path);
        }

        @Override
        protected int getResult(int result, int number) {
            return result + number;
        }

    }

}

템플릿 콜백 패턴 - 예제

public class FileProcessor {

    private String path;

    public FileProcessor(String path) {
        this.path = path;
    }

    public final int process(BiFunction<Integer, Integer, Integer> operation) {
        try(BufferedReader reader = new BufferedReader(new FileReader(path))) {
            int result = 0;
            String line = null;
            while((line = reader.readLine()) != null) {
                result = operation.apply(result, Integer.valueOf(line));
            }
            return result;
        } catch (IOException e) {
            throw new IllegalArgumentException(path + "에 해당하는 파일이 없습니다.", e);
        }
    }
//    protected abstract int getResult(int result, int number);
}
public class Client {

    public static void main(String[] args) {
        FileProcessor fileProcessor = new FileProcessor("number.txt");
        System.out.println(fileProcessor.process((a, b) -> a + b));
    }

}

완벽 공략 37. 디폴트 메서드와 Object 메서드

인터페이스의 디폴트 메서드로 Object 메서드(toString, hashCode, equals)를 재정의 할 수 없는 이유