'클래스가 어떤 인터페이스를 구현한다는 것은 자신의 인스턴스로 무엇을 할 수 있는지를 클라이언트에 얘기해주는 것이다.
인터페이스는 오직 이 용도로만 사용해야한다.'
인터페이스가 잘못 사용된 예시 - 상수 인터페이스)
PhysicalConstants 인터페이스는 static fianl 상수들로 이루어져 있다.
이게 왜 잘못된 사용된 인터페이스냐면
상수는 외부 인터페이스가 아니라 클래스 내부 구현에 해당하는데
상수 인터페이스를 구현하는 것은 내부 구현을 클래스의 API로 노출하는 것이기 때문이다.
public interface PhysicalConstants {
static final double AVOGADROS_NUMBER = 6.022_140_857e23;
static final double BOLTZMANN_CONSTANT = 1.380_648_52e-23;
static final double ELECTRON_MASS = 9.109_383_56e-31;
}
상수 인터페이스를 implements 했을 시 문제점
- 사용자에게 혼란을 준다.
- 클라이언트 코드가 내부 구현에 해당하는 이 상수들에게 종속되게 한다.
final이 아닌 클래스가 상수 인터페이스를 구현한다면 모든 하위 클래스의 이름공간이
그 인터페이스가 정의한 상수들로 오염되어 버린다.
대안
✅ 열거 타입으로 나태내기 적합한 상수라면 열거 타입으로 만들어 공개하자
✅ 인스턴스화할 수 없는 유틸리티 클래스에 담아 공개하자
💡유틸리티 클래스 - static 메서드, static 필드만을 담은 클래스(보통 유틸성 클래스로 helper 성격을 갖는다.)
유틸리티 클래스에 대한 블로그 링크를 첨부한다.
https://be-study-record.tistory.com/24
정적 유틸리티 클래스 (Static Utility Class)
static method와 static field 만을 담은 클래스. 보통 유틸성 클래스로 helper의 성격을 갖는 클래스. 이런 클래스들은 클래스 메서드와 클래스 인스턴스이니 객체 인스턴스가 필요없는 클래스여서 privat
be-study-record.tistory.com
https://spongeb0b.tistory.com/100
[Java] 유틸리티 클래스란 무엇인가?
유틸리티 클래스란 무엇인가? 어려운 개념은 없고 그냥 용어이다. 유틸리티 클래스는 인스턴스 메서드와 인스턴스 변수를 일절 제공하지 않고 정적 메서드와 변수만을 제공하는 클래스를 뜻한
spongeb0b.tistory.com
상수 인터페이스 PhysicalConstants의 유틸리티 클래스 버전 예시)
// 상수 interface 대신 상수 utility 클래스를 만들자!
public class PhysicalConstants {
private PhysicalConstants(){ } //인스턴스화 방지
static final double AVOGADROS_NUMBER = 6.022_140_857e23;
static final double BOLTZMANN_CONSTANT = 1.380_648_52e-23;
static final double ELECTRON_MASS = 9.109_383_56e-31;
}
💡 숫자 리터럴이 5자리 이상이라면 _(밑줄)을 사용하는 걸 고려해보자
_(밑줄)은 리터럴 값에 아무런 영향을 끼치지 않으면서, 가독성을 높여준다.
십진수 리터럴도 _(밑줄)을 사용해 세 자릿씩 묶어주는 것이 좋다.
유틸리티 클래스에 정의된 상수를 클라이언트에서 사용하려면 클래스 이름까지 함께 명시해야한다.
ex)
PhysicalConstants.AVOGADROS_NUMBER
유틸리티 클래스의 상수를 빈번하게 사용한다면 정적 임포트(static import)해서 클래스 이름을 생략할 수 있다.
💡정적 임포트(static import)
static멤버를 호출할 때 클래스명이 생략 가능
코드가 간결해지고 특정 클래스의 static 멤버를 자주 사용할 때 편리
어떤 클래스의 정적 메소드 사용시 해당 클래스를 임포트 한 뒤,
'클래스.정적메소드' 이런식으로 사용해야한다.
하지만 메소드를 사용할때마다 클래스명을 입력하기 번거로울 수 있다.
정적 임포트를 사용하면 클래스명을 생략하고, 메소드를 접근해서 사용할 수 있다.
사용방법은 기본 import에서 static 키워드만 붙이면 ok!
예시_1)
import static java.lang.Integer.*; // Integer 클래스의 모든 static멤버
import static java.lang.Math.random; //Math.random()만 import. 괄호는 붙이지 않는다.
import static java.lang.System.out; //이렇게 하면 System.out을 out만으로 참조가능
import static java.lang.Math.abs;
import static java.lang.Math.PI; // 정적 메소드 외의 정적 멤버 변수도 static import의 대상이 됨
//static import문 선언 전
System.out.println(Math.random());
System.out.println(Math.PI);
int i = Math.abs(-3);
//static import문 선언 후
out.println(random());
out.println(PI);
int i = abs(-3);
예시_2)
import static effectivejava.chapter4.item22.constantutilityclass.PhysicalConstants.*;
public class Test{
double atoms(double mols){
return AVOGADROS_NUMBER * mols;
}
}
결론
인터페이스는 타입 정의 용도로만 사용해라~~
'🤓 스터디 > 이펙티브 자바' 카테고리의 다른 글
[아이템 24] 멤버 클래스는 되도록 static으로 만들라 (0) | 2023.04.07 |
---|---|
[아이템 23] 태그달린 클래스보다는 클래스 계층구조를 활용하라 (0) | 2023.04.05 |
[아이템 21] 인터페이스는 구현하는 쪽을 생각해 설계하라 (0) | 2023.03.31 |
[아이템20] 추상 클래스보다는 인터페이스를 우선하라 (0) | 2023.03.31 |
[아이템19] 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라 (0) | 2023.03.31 |
댓글