IoC라는 약자로 많이 사용되는 제어의 역전(Inversion of Control)이라는 용어가 있다. 스프링을 통해 일반 개발자에게는 많이 알려진 용어이지만, 개념은 상당히 오래전부터 있었다.
1. 오브젝트 팩토리
지금까지는 문제가 많은 DAO를 깔끔한 구조로 리팩토링 하는 작업을 진행했다. 그 과정에서 생략한 부분이 바로 클라이언트 UserDAOTest이다. UserDAOTest는 기존에 UserDAO가 직접 담당하던 기능, 즉 어떤 ConnectionMaker 구현 클래스를 사용할지를 결정하는 기능을 엉겁결에 떠맡았다고 볼 수 있다. UserDAO가 ConnectionMaker 인터페이스를 구현한 특정 클래스로 부터 완벽하게 독립할 수 있도록 UserDAO의 클라이언트인 UserDAOTest가 그 수고를 담당하게 된거다.
그런데 여기서 개발자라면 의문을 가질 것이다.
UserDAO의 기능이 정상동작하는지 확인하기 위한 클래스가 왜 다른 책임까지 떠맡는거지?
그러기 때문에 이것 또한 분리하고자 한다. 이렇게 분리될 기능은 UserDAO와 ConnectionMaker 구현 클래스의 오브젝트를 만드는 것과, 그렇게 만들어진 두 개의 오브젝트가 연결돼서 사용될 수 있도록 관계를 맺어주는 것이다.
팩토리
분리시킬 기능을 담당할 클래스를 하나 만든다. 이 클래스의 역할은 객체의 생성 방법을 결정하고 그렇게 만들어진 오브젝트를 돌려주는 것인데, 이런 일을 하는 오브젝트를 흔히 팩토리(Factory)라고 부른다. 이는 디자인 패턴에서 말하는 특별한 문제를 해결하기 위해 사용되는 추상 팩토리 패턴이나 팩토리 메소드 패턴과는 다르니 혼동하지 않는게 좋다.
단지 오브젝트를 생성하는 쪽과 생성된 오브젝트를 사용하는 쪽의 역할과 책임을 깔끔하게 분리하려는 목적으로 사용하는 것이다.
어떻게 만들지와 어떻게 사용할지는 완전히 다른 관심사이다.
팩토리 역할을 맡을 클래스를 DaoFactory라고 한다. 그리고 UserDaoTest에 담겨있던 UserDao, ConnectionMaker 관련 생성 작업을 DaoFacotry로 옮기고 UserDaoTest에서는 DaoFacotry에 요청해서 미리 만들어진 UserDao 오브젝트를 가져와 사용하게 만든다.
public class DaoFactory {
public UserDao userDao() {
ConnectionMaker connectionMaker = new DConnectionMaker();
UserDao userDao = new UserDao(connectionMaker);
return userDao;
}
}
DaoFactory의 UserDao메소드를 호출하면 DConnectionMaker를 사용해 DB Connection을 가져오도록 이미 설정된 UserDao 오브젝트를 돌려준다. UserDaoTest는 이제 UserDao가 어떻게 만들어지는지 어떻게 초기화되어 있는지 신경쓰지 않고 팩토리로부터 UserDao 오브젝트를 받아다가, 자신의 관심사인 테스트를 위해 활용하기만 하면 된다.
수정된 UserDaoTest 코드는 아래와 같다.
public class UserDaoTest {
public static void main(String[] args) throws ClassNotFoundException, SQLException{
/*
* ConnectionMaker connectionMaker = new DConnectionMaker(); UserDao userDao =
* new UserDao(connectionMaker);
*/
UserDao dao = new DaoFactory().userDao();
}
}
위에서 설명한 것과 같이 UserDao가 어떻게 만들어지는지 어떻게 초기화되어 있는지 신경쓰지 않고 팩토리로 부터 UserDao 오브젝트를 받아다가 자신의 관심사를 테스트하기만 하면 된다.
설계도로서의 팩토리
이렇게 분리된 오브젝트들의 역할과 관계를 분석했다.
UserDao와 ConnectionMaker는 각 각 애플리케이션의 핵심적인 데이터 로직과 기술 로직을 담당하고 있고, DaoFactory는 이런 애플리케이션의 오브젝트들을 구성하고 그 관계를 정의하는 책임을 맡고 있음을 알 수 있다. 전자가 실질적인 로직을 담당하는 컴포넌트라면, 후자는 애플리케이션을 구성하는 컴포넌트의 구조와 관계를 정의한 설계도 같은 역할을 한다고 볼 수 있다.
설계도라고 하면 거창한 것 같지만, 간단히 어떤 오브젝트가 어떤 오브젝트를 사용하는지를 정의해놓은 코드라고 생각하면 된다.
이런 작업이 애플리케이션 전체에 걸쳐 일어난다면 컴포넌트의 의존관계에 대한 설계도와 같은 역할을 하게 될 것이다.
아래 그림은 DaoFactory를 적용한 구조를 이런 관점으로 구분한 그림이다.
이제 N사와 D사에 UserDao를 공급할 때, UserDao, ConnectionMaker와 함께 DaoFactory도 제공한다.
UserDao와 달리 DaoFactory는 소스를 제공한다. 새로운 ConnectionMaker 구현 클래스로 변경이 필요하면 DaoFactory를 수정해서 변경된 클래스를 생성해 설정해주도록 코드를 수정해주면 된다.
이렇게만 한다면 우리는 우리의 핵심 기술이 담긴 UserDao는 변경이 필요 없게되고 안전하게 소스코드를 보존할 수 있다. 동시에 DB 연결 방식은 자유로운 확장이 가능하다.
DaoFactory를 분리했을 때 얻을 수 있는 장점은 매우 다양하다. 그중에서도 애플리케이션의 컴포넌트 역할을 하는 오브젝트와 애플리케이션의 구조를 결정하는 오브젝트를 분리했다는 데 가장 의미가 있다.
'Programming > Spring' 카테고리의 다른 글
[오브젝트와 의존관계] - 관계 설정 책임의 분리 (0) | 2025.05.03 |
---|---|
[오브젝트와 의존관계] - DAO의 확장 (1) | 2025.05.03 |
[오브젝트와 의존관계] - 관심사의 분리 (0) | 2025.05.03 |
[오브젝트와의존관계] - DAO (0) | 2025.05.03 |
[Spring] 파일 업로드 (0) | 2024.05.26 |