티스토리 뷰

ETC

[Objects] 객체와 의존성

annajinee 2019. 8. 19. 02:14

조영호님의 우아한 세미나에 대해 정리한 것으로 자세한 내용은 아래 영상에서 확인 하실 수 있습니다.

영상 링크: https://www.youtube.com/watch?v=dJ5C4qRqAgA&list=PL8D2Xb3AlX8FHqzMLpEMHqXClbh839UYv


객체를 얘기 할때 가장 많이 나오는 얘기가 '역할’이나 '책임’인데요
실제적으로 역할이나 책임이 필요한건 ‘어떻게 의존성을 관리하느냐’ 입니다.

이 영상에서 중점적으로 다루는 부분은 아래와 같습니다.


  • 어떻게 의존성을 관리하는게 좋은 의존성인가
  • 의존성이 관리하는 방법에 따라서 설계가 어떻게 바뀌는가

설계와 의존성?

설계란, 어떤 클래스에 어떤 코드를 넣어야 하는지 코드를 어떻게 배치할 것 인가에 대한 의사 결정입니다.

그럼 어디다 어떻게 코드들을 배치 해야 하는가

변경 되는 코드들은 같이 넣고, 같이 변경되지 않은 코드들은 따로 넣는데요
여기서의 핵심은 의존성 입니다. 변경에 초점을 맞춰 의존성에 따라 배치 하게 되는거죠.

의존성(Dependency)에 대한 의미를 잠시 살펴 보자면,
아래와 같이 A 클래스가 B 클래스 를 의존 하고 있다면 B 클래스가 변경 될때 A 클래스도 변경 될 수 있다는 의미입니다.

depends on
A
B

그렇다고 B가 바뀐다고 A가 무조건 바뀌지 않습니다.
설계를 잘 하게 된다면 B 클래스의 내부가 바뀌더라도 A클래스에 영향이 없을 수 있습니다.

의존성(Dependency)는 크게 두가지로 나눌 수 있는데요,
Class 사이의 의존성(Dependency)와 Package 사이의 의존성(Dependency)로 나눌 수 있습니다.

먼저 Class 사이의 의존성(Dependency)을 살펴 보겠습니다.


클래스(Class) 사이의 의존성

class 사이의 의존성은 아래 네가지로 분류 될 수 있습니다.


  • 연관관계 (Association)
  • 의존관계 (Dependency)
  • 상속간계 (Inharitance)
  • 실체화관계 (Realization)

아까와 같이 A가 B를 의존 하는 경우를 예로 들겠습니다.

A
B

연관 관계란, ‘A에서 B로 이동 할 수 있어요’ 라는 의미이며 코드 상에서는 아래와 같이 객체 참조가 있는 경우입니다.

Class A {
    private B b;
}

의존 관계란, 파라미터나 리턴타입에 그 타입이 나오거나 메소드에서 그 타입의 인스턴스를 생성하는 경우입니다.
연관관계는 A에서 B로 갈 수 있는 영구적인 경로가 있다고 볼 수 있고 의존 관계는 협력을 하는 일시적으로 관계를 맺는 경우 입니다.

Class A {
    public method(B b){
	    return new B();
    }
}

그리고 상속 관계는 B 클래스의 구현을 A가 상속 받는 관계인데요 계승을 받기 때문에 B가 변경 될 경우 A도 같이 변경 되게 됩니다.

Class A extends B{
}

실체화 관계는 인터페이스를 implement하는 관계입니다.
상속관계와 실체화 관계의 차이는 상속은 구현이 바뀌면 영향을 받을 수 있고, 실체화 관계는 인터페이스의 오퍼레이션 시그너처가 바뀌었을 경우에만 영향을 받습니다.

Class A implements B{
}

패키지(Package) 사이의 의존성

패키지에서의 의존성이란 패키지에 포함된 클래스들 사의의 의존성입니다.

depends on
A
B

패키지 간의 의존 관계에 있다는 것은
위에서 설명한 클래스간에 연관관계나 의존관계와 같은 어떠한 의존 관계가 있어
패키지 B에 있는 클래스가 바뀔 때 패키지 A에 있는 클래스가 변경될 수 있다는 것을 말합니다.
의존성을 파악할때 간단하게 확인 하는 방법은 클래스를 열었을때 상단에 import에 따른 패키지를 확인 할 수 있는데요 그럼 depency가 있다고 볼 수 있습니다.


설계 시 의존성 가이드

저자가 제시한 좋은 의존성을 관리하기 위한 몇 가지 규칙은 아래와 같습니다.


  1. 양방향 의존성을 피하라
  2. 다중성이 적은 방향으로 선택하라 (oneToMany보다 ManyToOne방식으로)
  3. 의존성이 없다면 제거하라
  4. 패키지 사이의 의존성 사이클 제거 (양방향 의존성 x)

양방향 의존성을 피하라

첫 번째는 양방향 의존성을 피하는 것입니다.
아래와 같이 양방향 예를 보면 A가 변할 경우 B도 변하며 B가 변할 경우 A도 변하게 됩니다.

Bi-Directional (양방향)

A
B
class A {
    private B b;
	
	public void setA(B b){
		this.b = b;
		this.b.setA(this);
	}
}
class B {
	private A a;
	public void setA(A a){
		this.a = a;
}

이는 하나의 클래스를 어거지로 분리 해둔 것으로 볼 수 있는데요 A클래스에서 set메서드를 콜 할경우 B 클래스의 set메서드를 콜하고 있어 A와 B사이의 관계를 항상 동기화를 해야 합니다. 이러한 경우 성능 이슈 뿐만 아니라 싱크를 맞출 때 많은 버그를 일으킬 수 있기에 지양해야 합니다. 위 코드는 아래와 같이 단방향 형식으로 변경 할 수 있습니다.

Uni-Directional (단방향)

A
B
class A {
    private B b;
	
	public void setA(B b){
		this.b = b;
	}
}
class B {
}

다중성이 적은 방향으로 선택하라

아래의 One-To-Many 예와 같이 List나 Collection이나 Set같은 것들을 인스턴스 변수로 가지면, 다양한 이슈가 발생할 가능성이 있습니다.
JPA에서의 성능 이슈나 그 객체들의 관계를 유지하기 위해서는 다양한 노력들이 필요하여 가급적이면 다중성이 적은 방향으로 의존성을 선택하는 방법이 좋습니다.

One-To-Many (일대다)

1.A
*.B
class A {
    private Collection<B> bs;
}
class B {
}

Many-To-One (다대일)

*.B
1.A
class A {
}
class B {
    private A a;
}

의존성이 없다면 제거하라

가장 좋은 것은 의존성이 없을 경우는 의존성을 제거하는 것입니다.

Uni-Directional (단방향)

A
B
class A {
    private B b;
}
class B {
}

None (없음)

class A {
}
class B {
}

패키지 사이의 의존성 사이클은 제거하라

패키지 사이에서는 양방향의 의존성이 있어서는 안됩니다. 여기서 양방향 의존성은 사이클이라고 표현하는데요, 만약 패키지 3개가 있는데 패키지 사이의 dependency를 따라갔을 때 다시 원래 지점으로 돌아오는 경우는 피하셔야 합니다.
이러한 경우는 하나의 패키지가 변경 될 경우 다 같이 바뀌게 되어 하나의 패키지로 볼 수 있습니다.

packageA
pacakageB
packageB
pacakageB
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함