의존성
두 클래스 A, B가 있을 때 어느 한 쪽이 변화가 생길 때 다른 한 쪽도 함께 변경될 가능성이 있는 경우를 의존성이 있다고 말한다.
여기서 변경이란
클래스의 이름 변경, 메서드의 이름 변경, 메서드의 구현 변경 등을 의미한다.
의존에는 클래스 간 의존성과 패키지 간 의존성이 존재한다.
클래스 의존성의 종류
연관 관계 Association
1 | class A { |
A에서 B로 연결되어 있는 관계를 의미한다. 쉽게 말해 A에서 B의 객체 참조가 있는 경우를 의미한다. A라는 클래스에 B로 가는 영구적인 연결 통로가 생긴다.
의존 관계 Dependency
1 | class A { |
코드 상에서 인자 혹은 리턴 값으로 해당 타입을 사용하거나 메서드 안에서 해당 인스턴스를 생성하면 의존 관계이다. 이 관계는 해당 메서드를 사용할 때 일시적으로 맺어지는 관계이다. (영구적인 관계인 연관 관계와 다르다.)
상속 관계 Inheritance
1 | class A extends B { ... } |
상속 관계는 B 클래스의 구현을 그대로 가져와서 재사용하는 방식이다. 그래서 B 클래스의 구현이 변경되면 해당 구현을 사용하고 있던 A 클래스에 영향이 생긴다.
실체화 관계 Realization
1 | class A implements B { ... } |
실체화 관계는 인터페이스 B의 시그니처만 가져와서 사용하는 방식이다. 상속 관계와는 다르게 시그니처가 변경되지 않는 한 A 클래스에 영향이 생기지 않는다.
패키지 의존성
패키지 의존성은 A 패키지의 클래스 중 어느 하나라도 B 패키지의 클래스에 의존하는 경우 A 패키지가 B 패키지에 의존함을 의미한다.
좋은 설계를 위한 의존성 규칙
양방향 의존성을 피하라
양방향 Bi-Directional
1 | class A { |
A와 B가 서로 의존한다는 의미는 A가 변할 때 B가 변할 수 있고, B가 변할 때 A가 변할 수 있다는 의미이다. 이런 경우 원래 이 두 클래스가 하나의 클래스로 묶어야 될 수 있다.
양방향 의존 관계에서는 setter 메서드를 사용할 때 동기화 해줘야 한다.
동기화를 왜 해줘야 하는 지 코드로 간략하게 알아보자.
만약 A와 B에서 주석으로 동기화라고 적혀 있는 코드가 없는 상태로 setter를 사용한다고 가정해보자.
1 | A a1 = new A(); |
이렇게 양방향은 고려해야 할 부분이 많고 예상하지 못한 버그가 발생할 수 있다.
다중성이 적은 방향을 선택하라.
즉 일대다 대신 다대일 관계를 선택하는 게 좋다. 일대다를 JPA를 사용하다보면 N+1 문제에서 큰 성능 저하를 일으키게 된다.
1 | // 일대다 관계 (비추!) |
패키지 사이의 의존성 사이클을 제거하라
의존성 사이클은 여러 패키지의 의존성 방향이 결국 연결되는 것을 의미한다. 크게 보면 결국 양방향 의존인 셈이다. 패키지가 양방향 의존하게 되면 하나가 바뀌면 다같이 바뀌게 될 가능성이 존재한다는 의미이다. 즉 원래 같이 묶여야 될 패키지라는 의미일 수 있다.
구체적인 실습은 2편에서 해보자!