독서/토비의 스프링 Ⅰ

1장 오브젝트와 의존관계 (1)

봄의 개발자 2024. 10. 31.
728x90
반응형

1.2 DAO의 분리

  • 관심사의 분리

개발자가 객체를 설계할 때 가장 염두에 둬야 할 사항은 바로 미래의 변화를 어떻게 대비할 것인가이다.

변화가 한 번에 한 가지 관심에 집중돼서 일어난다면, 한 가지 관심이 한 군데에 집중되게 해야한다.

즉 관심이 같은 것끼리는 모으고, 관심이 다른 것은 따로 떨어져 있게 하는 것이다.

 

슈퍼클래스에 기본적인 로직의 흐름(커넥션 가져오기, SQL 생성, 실행, 반환)을 만들고, 그 기능의 일부를 추상 메소드나 오버라이딩이 가능한 protected 메소드 등으로 만든 뒤 서브클래스에서 이런 메소드를 필요에 맞게 구현해서 사용하도록 하는 방법을 디자인 패턴에서 템플린 메소드 패턴이라고 한다. 이는 스프링에서 애용된다.

 

서브클래스에서 구체적인 오브젝트 생성 방법을 결정하게 하는 것을 팩토리 메소드 패턴이라 한다.

중요한 건 상속구조를 통해 성격이 다른 관심사항을 분리한 코드를 만들어내고, 서로 영향을 덜 주도록 했는지를 이해해야 한다.

 

그러나 이러한 방법의 단점은 상속을 사용했다는 것이다. 상속 자체는 간단해 보이고 편리하게 느껴지지만 사실 많은 한계점이 있다.

자바는 다중 상속을 허용하지 않는다. 그리고 상속을 통한 상하위 클래스의 관계는 생각보다 밀접하다.

 

1.3 DAO의 확장

모든 오브젝트는 변한다. 데이터 액세스 로직을 어떻게 만들 것인가와 DB 연결을 어떤 방법으로 할 것인가 라는 두 개의 관심을 상하위 클래스로 분리시켰을 때, 이 두 개의 관심은 변화의 성격이 다르다.

변화의 성격이 다르다는 것은 변화의 이유와 시기, 주기 등이 다르다는 뜻이다.

추상 클래스를 만들고 이를 상속한 서브 클래스에서 변화가 필요한 부분을 바꿔서 쓸 수 있게 만드는 이유는 바로 이렇게 변화의 성격이 다른 것을 분리해서, 서로 영향을 주지 않은 채로 각각 필요한 시점에 독립적으로 변경할 수 있게 하기 위해서다.

그러나 여러가지 단점이 많은 상속이라는 방법을 사용했다는 사실이 불편하게 느껴진다.

 

  • 클래스의 분리

독립된 메소드를 만들어 분리 -> 상하위 클래스 분리 -> 완전히 독립적인 클래스로 분리

dao가 특정 클래스와 그 코드에 종속적이기 때문에 이를 자유롭게 확장하기가 힘들다.

 

  • 인터페이스의 도입

클래스를 분리하면서 이런 문제를 해결할 수 없을까?

가장 좋은 해결책은 두 개의 클래스가 서로 긴밀하게 연결되어 있지 않도록 중간에 추상적인 느슨한 연결고리를 만들어주는 것이다.

추상화란 어떤 것들의 공통적인 성격을 뽑아내어 이를 따로 분리해내는 작업이다.

자바가 추상화를 위해 제공하는 가장 유용한 도구는 인터페이스이다.

 

인터페이스는 자신을 구현한 클래스에 대한 구체적인 정보는 모두 감춰버린다. 결국 오브젝트를 만들려면 구체적인 클래스를 하나 선택해야하지만 인터페이스로 추상화해놓은 최소한의 통로를 통해 접근하는 쪽에서는 오브젝트를 만들 때 사용할 클래스가 무엇인지 몰라도 된다.

 

인터페이스는 어떤 일을 하겠다는 기능만 정의해놓은 것이다. 따라서 인터페이스에는 어떻게 하겠다는 구현 방법은 나타나 있지 않다. 그것은 인터페이스를 구현한 클래스들이 알아서 결정할 일이다.

 

  • 관계설정 책임의 분리

클래스 사이에 관계가 만들어진다는 것은 한 클래스가 인터페이스 없이 다른 클래스를 직접 사용한다는 뜻이다. 따라서 클래스가 아니라 오브젝트와 오브젝트 사이의 관계를 설정해줘야 한다. 오브젝트 사이의 관계는 런타임 시에 한쪽이 다른 오브젝트의 레퍼런스를 갖고 있는 방식으로 만들어진다.

 

오브젝트 사이의 관계가 만들어지려면 일단 만들어진 오브젝트가 있어야 하는데, 직접 생성자를 호출해서 직접 오브젝트를 만들 수도 있지만 외부에서 만들어 준 것을 가져오는 방법도 있다. 

 

외부에서 만든 오브젝트를 전달받으려면 메소드 파라미터나 생성자 파라미터를 이용하면 된다.

 

하나의 오브젝트가 동작하려면 결국 특정 클래스의 오브젝트와 관계를 맺게 되는데, 이건 클래스 사이에 관계가 만들어진 것이 아니라 단지 오브젝트 사이에 다이나믹한 관계가 만들어지는 것이다.

이 차이를 잘 구분해야 한다. 클래스 사이의 관계는 코드에 다른 클래스 이름이 나타나기 때문에 만들어지는 것이다.

하지만 오브젝트 사이의 관계는 그렇지 않다. 코드에서는 특정 클래스를 전혀 알지 못하더라도 해당 클래스가 구현한 인터페이스를 사용했다면, 그 클래스의 오브젝트를 인터페이스 타입으로 받아서 사용할 수 있다. 이는 객체지향 프로그래밍의 다형성이라는 특징 덕분에 가능하다.

 

오브젝트 사이에 런타임 사용관계 또는 링크 또는 의존관계라고 불리는 관계를 맺어주면 된다.

 

  • 원칙과 패턴

1. 개방 폐쇄 원칙

깔끔한 설계를 위해 적용 가능한 객체지향 설계 원칙 중 하나다.

클래스나 모듈은 확장에는 열려 있어야 하고 변경에는 닫혀 있어야 한다라는 의미이다.

 

인터페이스를 통해 제공되는 확장 포인트는 확장을 위해 활짝 개방되어 있지만, 인터페이스를 이용하는 클래스는 자신의 변화가 불필요하게 일어나지 않도록 굳게 폐쇄되어 있다.

 

2. 높은 응집도와 낮은 결합도

응집도가 높다는 것은 하나의 모듈, 클래스가 하나의 책임 또는 관심사에만 집중되어 있다는 뜻이다. 불필요하거나 직접 관련이 없는 외부의 관심과 책임이 얽혀 있지 않으며, 하나의 공통 관심사는 한 클래스에 모여있다.

 

응집도가 높다는 것은 변화가 일어날 때 해당 모듈에서 변하는 부분이 크다는 것이다. 즉 변경이 일어날 때 모듈의 많은 부분이 함께 바뀐다면 응집도가 높다고 말할 수 있다.

 

낮은 결합도는 높은 응집도보다 더 민감한 원칙이다. 책임과 관심사가 다른 오브젝트 또는 모듈과는 낮은 결합도, 즉 느슨하게 연결된 형태를 유지하는 것이 바람직하다.

결합도가 낮아지면 변화에 대응하는 속도가 높아지고, 구성이 깔끔해진다. 확장하기에도 편리하다.

 

여기서 결합도란 하나의 오브젝트가 변경이 일어날 때에 관계를 맺고 있는 다른 오브젝트에게 변화를 요구하는 정도라고 설명할 수 있다.

낮은 결합도란 결국, 하나의 변경이 발생할 때 마치 파문이 이는 것처럼 여타 모듈과 객체로 변경에 대한 요구가 전파되지 않는 상태이다.

 

3. 전략 패턴

전략 패턴은 디자인 패턴의 꽃! 개방 폐쇄 원칙의 실현에도 가장 잘 들어맞는 패턴

자신의 기능 맥락에서, 필요에 따라 변경이 필요한 알고리즘을 인터페이스를 통해 통째로 외부로 분리시키고 이를 구현한 구체적인 알고리즘 클래스를 필요에 따라 바꿔서 사용할 수 있게 한다.

-> 여기서 알고리즘은 독립적인 책임으로 분리가 가능한 기능을 뜻함

 

컨텍스트를 사용하는 클라이언트는 컨텍스트가 사용할 전략을 컨텍스트의 생성자를 통해 제공해주는 것이 일반적이다.

 

1.4 제어의 역전(IoC)

  • 오브젝트 팩토리

팩토리: 객체의 생성 방법을 결정하고 그렇게 만들어진 오브젝트를 돌려주는 역할을 하는 클래스

* 디자인 패턴에서 말하는 특별한 문제를 해결하기 위해 사용되는 추상 팩토리 패턴이나 팩토리 메소드 패턴과는 다르니 혼동 금지!

 

단지 오브젝트를 생성하는 쪽과 생성된 오브젝트를 사용하는 쪽의 역할과 책임을 깔끔하게 분리하려는 목적으로 사용

어떻게 만들지와 어떻게 사용할지는 분명 다른 관심이다.

이러한 팩토리는 오브젝트들을 구성하고 그 관계를 정의하는 책임을 맡고 있다.

 

 

 

 

 

728x90
반응형

댓글