연관관계 매핑
객체 연관관계와 테이블 연관관계의 차이점
- 객체는 참조(주소)값을 기준으로 연관관계를 맺는다.(단방향)
ex) X->Y , Y->X - 테이블은 외래키를 기준으로 연관관계를 맺는다. (JOIN operation , 양방향)
ex) X JOIN Y 는 Y JOIN X 도 가능하다.
단방향 연관관계
- 두 entity 중 어느 한쪽만 다른 한쪽을 참조하는 경우을 단방향이라고 한다.
ex) Serializable interface : 직렬화 가능함을 표시
marker interface는 2가지 측면에서 marker annotation 에 비해 유리하다.
특정 인터페이스를 구현한 class에만 적용하고 싶은 marker interface 가 있다고 하면 해당 인터페이스를 확장하면 된다.
Java가 기본으로 제공하는 annotation중 @Override는 상위 타입 method를 재정의하였을때 달릴 수 있다.
@Override annotation을 사용함으로 여러 가지 버그들을 컴파일 시점에 예방해 줄 수 있다.
예를 들어 다음과 같은 영어 알파벳 2개로 구성된 문자열을 표현하는 클래스가 있다고 할때, main method에서 26개의 소문자를 set에 넣어준뒤 출력하면 당연히 26개의 size가 출력되야하지만 실제로는 260 개의 size가 나온다.
1 | public class Bigram { |
그 이유는 바로 equals method를 실수로 parameter 를 Bigram type으로 받아 overrloading하였기 때문이다. @Override 를 붙여주면 바로 compile error를 보여준다.
따라서 상위 class의 method를 재정의하는 모든 method는 @Override annotation을 달 것을 권고한다.
도구나 프레임워크가 특별히 다뤄야 할 프로그램 요소에는 구분되는 명명 패턴을 적용해왔다 예를 들면 JUnit 은 버전 3까지 테스트 method 이름을 test로 시작하게끔 하였다.
명명 패턴의 단점은 다음과 같다.
예를 들면 클래스 이름에 TestSafetyMechanism이라고 명명한다고 하여도 해당 class에 있는 method들은 실행되지 않는다.
3. 매개변수 전달 방법이 없음
특정 예외가 터져야 성공하는 test가 있을때 매개변수로 예외 class type을 전달해줄수 없다.
Junit 4부터는 annotation을 명명패턴 대신에 도입하였다.
annotation에 관한 기본내용은 다음과 같다.
1 | package java.lang.annotation; |
enum type은 상속이 불가능하다.
확장한 타입의 원소는 기반 타입으로 받을 수 있지만, 반대로 기반 타입은 확장한 타입으로 받을 수 없으며, 기반 타입과 확장한 타입들의 원소를 모두 순회할 방법도 마땅치 않다.
그럼에도 불구하고 enum type의 확장시 유용한 경우가 종종 있는데, 그 예중에 하나가 연산 코드이다.
enum type은 상속이 불가능한 대신 interface 구현은 가능하다. 따라서 interface를 통해 간접적으로 확장이 가능하다.
client 가 접근할 interface를 두고, 그 interface의 구현체별로 enum type을 정의하는 방법이다.
client가 접근할 operation interface를 두고 operation interface의 구현체로 enum class를 생성하였다.
다음과 같이 식물 class가 있고 이 class를 LifeCycle enum type을 key로 set에 분류해서 담고 싶다고 가정하자.
1 | public class Plant { |
한가지 방법은 Set 배열에 ordinal method()로 가져온 LifeCycle Enum type의 index 값으로 배열에 indexing 해 저장하는 것이다.
1 | Set<Plant>[] plantsByLifeCycle = (Set<Plant>[]) new Set[Plant.LifeCycle.values().length]; |
위 코드는 다음과 같은 문제점을 가지고 있다.
EnumMap을 쓰면 위와 같이 ordinal method로 indexing 하는 단점을 제거해주고, 추가로 출력 문자열도 자체로 제공해준다.
EnumMap은 runtime에서 generic type 정보 제공을 위해 생성자에서 key 로 사용할 class 객체를 받는다.
1 | Map<Plant.LifeCycle, Set<Plant>> plantsByLifeCycle = new EnumMap<>(Plant.LifeCycle.class); |
열거한 값들이 주로 집합으로 사용될 경우, 예전에는 각 상수에 서로 다른 2의 거듭제곱 값을 할당한 정수 열거 패턴을 사용해왔다.
다음과 같이 비트별 OR를 사용해 여러 상수를 하나의 집합으로 모을 수 있으며, 이렇게 만들어진 집합을 bit field라 한다.
1 | public class Text { |
bit field의 문제점은 비트별 연산을 통해 집합 연산은 효율적으로 수행할 수 있으나, 정수 열거 상수의 단점들에 추가로 비트 필드값이 그대로 출력되면 해석하기 더 어렵다는 단점이 있다.
1 | /** |
대부분 열거타입 상수는 하나의 정수값과 대응되는데, ordinal method는 특정 상수가 그 열거타입에서 몇번쨰 위치인지를 반환하는 method이다. 예를 들면 아래와 같이 합주단 종류 enum type내에서 몇번쨰 위치하고 있는지 알아낼때 사용한다.
1 | public enum Ensemble { |
Enum type은 일정 개수의 상수 값을 정의한 다음 그 외의 값들은 허용하지 않는 타입이다. Enum Type은 다음과 같은 특징을 가지고 있다.
1 | public enum Day { |
(https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html)
1 | public abstract class Enum<E extends Enum<E>> |
상수당 자신의 instance를 하나씩 만들어 public static final 필드로 공개한다. (enum class내 상수는 public static final 필드와 같음 )
외부에서 접근할 수 있는 생성자를 제공하지 않는다. 때문에 singleton은 원소가 하나뿐인 열거타입이라고도 볼 수 있다.
1 | public class SetTest { |
위와 같이 Set의 API에 대한 학습테스트를 수행한다고 하였을떄 각 원소를 포함했는지 중복코드가 발생한다.
Junit 5부터는 이를 ParameterizedTest 로 테스트에 여러개의 매개변수를 넣어주게 해줌으로써 테스트 코드 리팩토링을 원할하게 해준다.
필요한 library dependency는 다음과 같다.
1 | // maven |