-
아이템 22 & 아이템 23 & 아이템 24 & 아이템 25Java/이펙티브 자바 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"; } }
'Java > 이펙티브 자바' 카테고리의 다른 글
아이템 27. 비검사 경고를 제거하라 (0) 2023.09.21 아이템26. 로 타입은 사용하지 말라. (0) 2023.09.18 아이템21. 인터페이스는 구현하는 쪽에서 생각해 설계하라. (0) 2023.09.05 아이템20. 추상 클래스보다 인터페이스를 우선하라. (0) 2023.08.31 아이템19. 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라. (0) 2023.08.30