본문 바로가기
Language/Java

이펙티브자바 규칙 19) 2015년 6월 21일- 일요일 스터디 카페 방문

by 태하팍 2015. 6. 21.
반응형
1. 이펙티브 자바 읽기(범위 : 규칙19,20,21)
인터페이스는 클라이언트 입장에서 보면 “알림이?(명세) 역할"을 한다. 즉, class로 구현할 것을 인터페이스는 미리 말해준다.
인터페이스 사용법 중에 실패한 것은 메소드도 없고 static final field만 존재하는 소위 "constant interface” 라 불린다.

// Constant interface antipattern - do not use!
public interface PhysicalConstants {
     // Avogadro's number (1/mol)
     static final double AVOGADROS_NUMBER = 6.02214199e23;
    // Boltzmann constant (J/K) 
    static final double BOLTZMANN_CONSTANT = 1.3806503e-23;
    // Mass of the electron (kg)
    static final double ELECTRON_MASS = 9.10938188e-31;
}

There are several constant interfaces in the Java platform libraries, such as java.io.ObjectStreamConstants
public interface ObjectStreamConstants {

/**
* Magic number that is written to the stream header.
*/
final static short STREAM_MAGIC = (short)0xaced;

/**
* Version number that is written to the stream header.
*/
final static short STREAM_VERSION = 5;

/* Each item in the stream is preceded by a tag
*/

/**
     ……… 


왜 사용하면 안되는가?
1. 인터페이스로 제공을 한다면 다음에 해당 Constant Interface의 상수를 class에서 사용하지 않는다고 해도 
    binary-compatibliliy(이진 호환성?)을 보장하기 위해 그 인터페이스를 계속 implements해야한다.

2.  비-final 클래스가 상수 인터페이스를 구현할 경우, 그 모든 하위 클래스의 이름 공간(namespace)이 해당 인터페이스의 상수들로 오염된다. ????? 뭔소리지??-_-;; 
원문 : 
If a nonfinal class implements a constant interface, all of its subclasses will have their namespaces polluted by the constants in the interface.

아마도 이런 뜻이 아닐까?
ex) 아래의 상수 인터페이스가 있다고 하면

/**
* Created by terrypark on 2015. 6. 21..
*/
public interface DoNotConstantInterfaceTest {

public static final Double ACET=4.5;
public static final Double VICTER=4.3;
public static final Double JINNY=4.1;
public static final Double HOIRU=4.4;
}

위의 인터페이스를 구현하는 클래스가 있고 그 클래스를 상속받은 클래스가 있을 것이다.(sub class)
이 자식 클래스에서 namespace가 ACET인 것을 사용한다고 하면???

DoNotConstantInterfaceTest Interface를 구현한 클래스!

/**
* Created by terrypark on 2015. 6. 21..
*/
public class DoNotTest implements DoNotConstantInterfaceTest {
public DoNotTest(){}
private double data;

public void getData(){
System.out.println(DoNotConstantInterfaceTest.ACET);
this.data = DoNotConstantInterfaceTest.HOIRU;
System.out.println(data);
}
}

위의 클래스의 자식 클래스(Sub Class)

/**
* Created by terrypark on 2015. 6. 21..
*/
public class DoNotTest2 extends DoNotTest {
public static final Double ACET=2.5;
private Double test;

public void getData2(){
System.out.println("DoNotTest2----start");
this.test = DoNotConstantInterfaceTest.ACET;
System.out.println(test);
System.out.println("DoNotTest2----end");
}
}

DoNotTest dt = new DoNotTest();
dt.getData();

DoNotTest2 dt2 = new DoNotTest2();
dt2.getData2();

의 결과는???

4.5
4.4
DoNotTest2----
4.5
DoNotTest2----
위를 드래그하면 답이 있음! ㅋㅋ 

이런 내용이 오염을 시키는 것으로 봐도 되는것인가??!!  모두에게 묻기!~

아니면 아래와 같이.. 헷깔리게 여러군데에서 사용하게 하는 아래의 형태가 오염된거라고 하는것인가?
/**
* Created by terrypark on 2015. 6. 21..
*/
public class DoNotTest2 extends DoNotTest {
public static final Double ACET=2.5;
private Double test;

public void getData2(){
System.out.println("DoNotTest2----start");
this.test = DoNotConstantInterfaceTest.ACET;
System.out.println(test);
System.out.println("DoNotTest2----end");

System.out.println(DoNotConstantInterfaceTest.ACET);
System.out.println(DoNotTest.ACET);
System.out.println(DoNotTest2.ACET);
}
}

위의 답은?
4.5
4.5
2.5

우어…1시간이 벌써 지났다..쿨럭;; 
anyways..위와 같은 좋지 않으니 사용하지 말라는 것이다.

이제는 그럼 뭘 쓰라는 말이냐? 어쩌라는거냐? 라는 말에 대한 답변이다.

상수를 API 일부로 공개하고 싶을 때는(역시나 라이브러리 느낌이 강하군..) 더 좋은 방법이 있다고 제시한다.
(이펙티브 규칙 19)

아래처럼 사용하면 된다.
생성자는 private으로 객체를 생성하지 못하게 한다. 그리고 아래처럼 static final로!! 즉, 규칙 3에 나오는 유틸리티 클래스로!
/**
* Created by terrypark on 2015. 6. 21..
*/
public class PrivateConstructTest {
private PrivateConstructTest(){}
public static final double AVO = 6.0;
}

또한, 위의 class를 접근하기 위해서는 아래처럼 클래스명을 붙여야 한다.
PrivateConstructTest.AVO
정적 임포트(static import)를 사용하면 클래스 이름을 제거할 수 있다! 
import static kr.pe.acet.PrivateConstructTest.*;

마지막으로 인터페이스는 Type을 정의할 때만 사용하라! 특정 상수를 API의 일부로 공개할 목적으로는
(api니깐 공통적으로 사용하자는 목적?!) 적절치 않다.


반응형