2022. 5. 26. 09:45ㆍ토비의 스터디
1.4.1 오브젝트 팩토리
지금까지 초난감 DAO를 리팩토링하였다.
그러나 UserDaoTest가 DAO의 클라이언트 오브젝트가 되면서,
어떤 ConnectionMaker 구현 클래스를 사용할지를 결정하는 기능을 떠맡게 되었다.
UserDao의 기능이 잘 동작하는지 테스트하려고 만든 것인데 다른 책임을 떠맡고 있으니 문제가 있어보인다.
그러니 이것도 분리하자.
객체의 생성 방법을 결정하고, 그렇게 만들어진 오브젝트를 돌려주는 클래스를 만들어보자.
이런 일을 하는 오브젝트를 흔히 팩토리(Factory)라고 부른다. 오브젝트를 생성하는 쪽과 생성된 오브젝트를 사용하는 쪽을 분리하기 위해 사용한다.
public class DaoFactory {
public UserDao userDao() {
ConnectionMaker connectionMaker = new NConnectionMaker();
UserDao dao = new UserDao(connectionMaker);
return dao;
}
}
userDao() 메소드를 호출하면, DConnectionMaker를
사용해 커넥션을 가져오도록 설정된 UserDao오브젝트를 돌려준다.
이제 UserDaoTest의 코드는 아래와 같다.
public class UserDaoTest {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
DaoFactory daoFactory = new DaoFactory();
UserDao dao = daoFactory.userDao();
}
}
1.4.2 오브젝트 팩토리의 활용
만약 DaoFactory에서 UserDao가 아닌 다른 DAO의 생성 기능을 넣으면 어떻게 될까?
AccountDao, MessageDao가 추가되었다고 해보자. 이 경우에 UserDao를 생성하는 userDao()메소드가 중복으로 사용될 것이다.
public class DaoFactory {
public UserDao userDao() {
ConnectionMaker connectionMaker = new NConnectionMaker(); //중복 코드 발생
return new UserDao(connectionMaker);
}
public AccountDao accountDao() {
ConnectionMaker connectionMaker = new NConnectionMaker();
return new AccountDao(connectionMaker);
}
public MessageDao messageDao() {
ConnectionMaker connectionMaker = new NConnectionMaker();
return new MessageDao(connectionMaker);
}
}
중복 코드는 분리가 가장 좋은 방법이다.
리팩토링한 코드
public class DaoFactory {
public UserDao userDao() {
return new UserDao(connectionMaker());
}
public AccountDao accountDao() {
return new AccountDao(connectionMaker());
}
public MessageDao messageDao() {
return new MessageDao(connectionMaker());
}
public ConnectionMaker connectionMaker() {
return new NConnectionMaker();
}
}
1.4.3 제어권의 이전을 통한 제어관계 역전
제어의 역전이라는 것은, 간단히 말하자면 프로그램의 제어 흐름 구조가 뒤바뀌는 것이다.
일반적인 흐름은 main()메소드와 같이 프로그램 시작 지점에서 사용할 오브젝트를 결정하고, 생성하고, 메소드를 호출하는 식의 작업이 반복된다. 이런 프로그램 구조에서 각 오브젝트는 프로그램 흐름을 결정하거나 사용할 오브젝트를 구성하는 작업에 능동적으로 참여한다.
이런 제어 흐름의 개념을 거꾸로 뒤집는 것이다. 제어의 역전에서는 오브젝트가 자신이 사용할 오브젝트를 스스로 선택하지 않는다. 당연히 생성하지도 않는다. 자신이 어떻게 생성되고 사용되는지도 알 수 없다.
모든 제어권한을 자신이 아닌 다른 대상에게 위임하기 때문이다.
서블릿을 생각해보자. 서블릿을 개발해서 서버에 배포할 수 있지만, 그 실행을 개발자가 직접 제어할 수 있는 방법은 없다. 대신 서블릿에 대한 제어권한을 가진 컨테이너가 적절한 시점에 서블릿 클래스의 오브젝트를 만들고 그 안의 메소드를 호출한다.
프레임워크도 제어의 역전 개념이 적용된 대표적인 기술이다. 확장해서 사용할 수 있도록 준비된 추상 라이브러리의 집합이 아니다.
라이브러리를 사용하는 애플리케이션 코드는 애플리케이션 흐름을 직접 제어한다. 동적하는 중에 필요한 기능이 있을 때 능동적으로 라이브러리를 사용할 뿐이다.
반면 프레임워크는 거꾸로 애플리케이션 코드가 프레임워크에 의해 사용된다. 프레임워크 위에 개발한 클래스를 등록하고, 프레임워크가 흐름을 주도하는 중에 개발자가 만든 코드를 사용하는 방식이다.
원래의 UserDao는 ConnectionMaker의 구현 클래스를 직접 결정하고 오브젝트를 만드는 제어권을 가지고 있었다. 하지만 지금은 DaoFactory에게 넘어갔다. UserDao 자신도 팩토리에 의해 수동적으로 생성되며, 사용할 오브젝트도 DaoFactory가 공급해주는 것을 수동적으로 사용해야 한다.
이것이 IoC(제어의 역전)이다.
스프링은 IoC를 모든 기능의 기초가 되는 기반 기술로 삼고 있으며, IoC를 극한까지 적용하고 있는 프레임워크다.
'토비의 스터디' 카테고리의 다른 글
[토비의 스터디 3.1] 1.6 싱글톤 레지스트리와 오브젝트 스코프 (0) | 2022.05.27 |
---|---|
[토비의 스프링 3.1] 1.5 스프링의 IoC (0) | 2022.05.27 |
[토비의 스프링 3.1] 1.3 DAO의 확장 (0) | 2022.05.25 |
[토비의 스프링 3.1] 1.2 DAO의 분리 - 포포 (0) | 2022.05.24 |
[토비의 스프링 3.1] 1.1 초난감 DAO - 포포 (0) | 2022.05.23 |