ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 아이템 22 & 아이템 23 & 아이템 24 & 아이템 25
    Java/이펙티브 자바 2023. 9. 7. 11:02

    아이템 22. 인터페이스는 타입을 정의하는 용도로만 사용하라.

    핵심 정리

    - 상수를 정의하는 용도로 인터페이스를 사용하지 말 것!

        ㆍ클래스 내부에서 사용할 상수는 내부 구현에 해당한다.

        ㆍ내부 구현을 클래스의 API로 노출하는 행위가 된다.

        ㆍ클라이언트에 혼란을 준다.

    public class MyClass implements PhysicalConstants{
        public static void main(String[] args) {
            System.out.println(PhysicalConstants.ELECTRON_MASS);
            System.out.println(BOLTZMANN_CONTANT);  // 상속 시 위와 같이 사용 가능 - 인터페이스의 의도(타입 정의) 오염
        }
    }

    - 상수를 정의하는 방법

        ㆍ특정 클래스나 인터페이스

        ㆍ열거형

        ㆍ인스턴스화 할 수 없는 유틸리티 클래스

    // 코드 22-2 상수 유틸리티 클래스 (140쪽)
    public class PhysicalConstants {
        private PhysicalConstants() {   // 인스턴스화 방지
        }
        
        // 아보가드로 수 (1/몰)
        public static final double AVOGADROS_NUMBER = 6.022_140_857e23;
        // 볼츠만 상수 (J/K)
        public static final double BOLTZMANN_CONST = 1.380_648_52e-23;
        // 전자 질량(kg)
        public static final double ELECTRON_MASS = 9.109_383_56e-31;
    }

     

    아이템 23. 태그 달린 클래스보다는 클래스 계층 구조를 활용하라.

    핵심 정리

    - 태그 달린 클래스의 단점

        ㆍ쓸데없는 코드가 많다.

        ㆍ가독성이 나쁘다.

        ㆍ메모리도 많이 사용한다.

        ㆍ필드를 final로 선언하려면 불필요한 필드까지 초기화해야 한다.

        ㆍ인스턴스 타입만으로 현재 나타내는 의미를 알 길이 없다.

    // 코드 23-1 태그 달린 클래스 - 클래스 계층구조보다 훨씬 나쁘다! (142쪽-143쪽)
    class Figure {
        enum Shape { RECTANGLE, CIRCLE }
    
        // 태그 필드 - 현재 모양을 나타낸다.
        final Shape shape;
    
        // 다음 필드들은 모양이 사각형(RECTANGLE)일 때만 쓰인다.
        double length;
        double width;
    
        // 다음 필드는 모양이 원(CIRCLE)일 때만 쓰인다.
        double radius;
    
        // 원용 생성자
        Figure(double radius) {
            shape = Shape.CIRCLE;
            this.radius = radius;
        }
    
        // 사각형용 생성자
        Figure(double lenght, double width) {
            shape = Shape.RECTANGLE;
            this.length = lenght;
            this.width = width;
        }
    
        double area() {
            switch(shape) {
                case RECTANGLE:
                    return length * width;
                case CIRCLE:
                    return Math.PI * (radius * radius);
                default:
                    throw new AssertionError(shape);
            }
        }
    }

    - 클래스 계층 구조만 바꾸면 모든 단점을 해결할 수 있다.

     

     

    아이템 24. 멤버 클래스는 되도록 static으로 만들라.

    핵심 정리 : 네 종류의 중첩 클래스와 각각의 쓰임

    - 정적 멤버 클래스

        ㆍ바깥 클래스와 함께 쓰일 때만 유용한 public 도우미 클래스. 예) Calculator.Operation.PLUS

    public class OutterClass {
        
        private static int number = 10;
        
        static private class InnerClass {
            void doSomething() {
                System.out.println(number);
            }
        }
    
        public static void main(String[] args) {
            InnerClass innerClass = new InnerClass();
            innerClass.doSomething();
        }
    }

    - 비정적 멤버 클래스

        ㆍ바깥 클래스의 인스턴스와 암묵적으로 연결된다.

        ㆍ어댑터를 정의할 때 자주 쓰인다.

        ㆍ멤버 클래스에서 바깥 인스턴스를 참조할 필요가 없다면 무조건 정적 멤버 클래스로 만들자.

    public class OutterClass {
        private int number = 10;
        
        private class InnerClass {
            void doSomething() {
                System.out.println(number);
            }
        }
    
        public static void main(String[] args) {
            InnerClass innerClass = new OutterClass().new InnerClass();
            innerClass.doSomething();
        }
    }

    - 익명 클래스

        ㆍ바깥 클래스의 멤버가 아니며, 쓰이는 시점과 동시에 인스턴스가 만들어진다.

        ㆍ비정적인 문맥에서 사용될 때만 바깥 클래스의 인스턴스를 참조할 수 있다.

        ㆍ자바에서 람다를 지원하기 전에 즉석에서 작은 함수 객체나 처리 객체를 만들 때 사용했다.

        ㆍ정적 팩터리 메서드르르 만들 때 사용할 수도 있다.

    - 지역 클래스

        ㆍ가장 드물게 사용된다.

        ㆍ지역 변수를 선언하는 곳이면 어디든 지역 클래스를 정의해 사용할 수 있다.

        ㆍ가독성을 위해 짧게 작성해야 한다.

     

    완벽 공략 - 어댑터 패턴

    : 기존 코드를 클라이언트가 사용하는 인터페이스의 구현체로 바꿔주는 패턴

    - 클라이언트가 사용하는 인터페이스를 따르지 않는 기존 코드를 재사용할 수 있게 해준다.

    public static void main(String[] args) {
        try(InputStream is = new FileInputStream("number.txt");
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader reader = new BufferedReader(isr)) {
            while(reader.ready()) {
                System.out.println(reader.readLine());
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    
    }

     

    아이템 25 톱 레벨 클래스는 한 파일에 하나만 담으라.

    핵심 정리

    - 한 소스 파일에 톱 레벨 클래스를 여러 개 선언하면 컴파일 순서에 따라 결과가 달라질 수 있다.

    - 다른 클래스에 딸린 부차적인 클래스는 정적 멤버 클래스로 만드는 것이 낫다.

        읽기 좋으며 private으로 선언해서 접근 범위도 최소한으로 관리할 수 있다.

    // 코드 25-3 톱레벨 클래스들을 정적 멤버 클래스로 바꿔본 모습 (151-152쪽)
    public class Test {
        public static void main(String[] args) {
            System.out.println(Utensil.NAME + Dessert.NAME);
        }
        
        private static class Utensil {
            static final String NAME = "pan";
        }
        
        private static class Dessert {
            static final String NAME = "cake";
        }
        
    }

     

     

    댓글

Designed by Tistory.