공부해봅시당

[스프링] 오브젝트와 의존관계 4 본문

STUDY/Spring

[스프링] 오브젝트와 의존관계 4

tngus 2022. 10. 14. 21:24

1.4. 제어의 역전(IoC)

IoC(Inversion of Control)이라는 용어가 있다.

IoC가 무엇인지 살펴보기 위해 UserDao 코드를 좀 더 개선해보겠다.

 

1.4.1. 오브젝트 팩토리

UserDaoTest는 기존에 UserDao가 직접 담당하던 기능, 즉 어떤 ConnectionMaker 구현 클래스를 사용할지를 결정하는 기능을 떠맡게 됨

 

테스트를 위한 클래스에서 다른 책임까지 떠맡게 됨

따라서 이것도 분리하는 것이 좋음

 

팩토리(Factory)

분리시킬 기능할 담당할 클래스를 하나 만들어보자

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

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

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

 

DaoFactory.java

package springbook.user.dao;

...

public class DaoFactory {
	public UserDao userDao() {
    	ConnectionMaker connectionMaker = new DConnectionMaker();
        UserDao userDao = new UserDao(connectionMaker);
        return userDao;
    }
}

 

UserDaoTest.java

public class UserDaoTest {
	public static void main(String[] args) throws ClassNotFoundException, SQLException {
    	UserDao dao = new DaoFactory().userDao();
    }
}

리팩토링 뒤에는 테스팅을 습관화 하자!

 

 

설계도로서의 팩토리

 

오브젝트 팩토리를 활용한 구조

UserDao와 달리 DaoFactory는 소스를 제공한다.

새로운 ConnectionMaker 구현 클래스로 변경이 필요하면 DaoFactory를 수정해서 변경된 클래스를 생생해 설정해주도록 코드를 수정하면 됨

 

1.4.2. 오브젝트 팩토리의 활용

DaoFactory에 UserDao가 아닌 다른 DAO의 생성 기능을 넣으면 어떻게 될짜?

AccountDao, MessageDao 등을 만들었다고 해보자.

 

ConnectionMaker 구현 클래스를 사용할지를 결정하는 기능이 중복되어 나타나게 된다.

 

public class DaoFactory {
	public UserDao userDao() {
    	return new UserDao(new DConnectionMaker());
    }
    
    public AccountDao accountDao() {
    	return new AccountDao(new DConnectionMaker());
    }
    
    public MessageDao messageDao() {
    	return new MessageDao(new DConnectionMaker());
    }
}

new DConnectionMaker라는 ConnectionMaker 구현 클래스의 인스턴스를 만드는 부분이 반복되어 나타난다.

 

이렇게 오브젝트 생성 코드가 중복되는 건 좋지 않은 현상이다.

 

DAO가 더 많아지면 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 DConnectionMaker();
    }
}

 

1.4.3. 제어권의 이전을 통한 제어관계 역전

제어의 역전


간단히 프로그램의 제어 흐름 구조가 뒤바뀌는 것

오브젝트가 자신이 사용할 오브젝트를 스스로 선택하지 않음
당연히 생성하지도 않음
또 자신도 어떻게 만들어지고 어디서 사용되는지 알 수 없음
모든 제어 권한을 자신이 아닌 다른 대상에게 위임하기 때문

Ex) 서블릿을 개발해서 서버에 배포할 수는 있지만, 그 실행을 개발자가 직접 제어할 수 있는 방법은 없음
서블릿 안에 main() 메소드가 있어서 직접 실행시킬 수 있는 것도 아님
대신 서블릿에 대한 제어 권한을 가진 컨테이너가 적절한 시점에 서블릿 클래스의 오브젝트를 만들고 그 안의 메소드를 호출함
이렇게 서블릿이나 JSP, EJB처럼 컨테이너 안에서 동작하는 구조는 간단한 방식이긴 하지만 제어의 역전 개념이 적용되어 있다고 볼 수 있음

제어권을 상위 템플릿 메소드에 넘기고 자신은 필요할 때 호출되어 사용되도록 한다는 제어의 역전 개념!

프레임워크와 라이브러리

프레임워크도 제어의 역전 개념이 적용된 대표적인 기술
프레임워크는 라이브러리의 다른 이름이 아님
프레임워크는 단지 미리 만들어둔 반제품이나, 확장해서 사용할 수 있도록 준비된 추상 라이브러리의 집합이 아님

라이브러리를 사용하는 애플리케이션 코드 > 애플리케이션 흐름 직접 제어
단지 동작 중 필요한 기능이 있을 때 능동적으로 라이브러리 사용

프레임워크 > 거꾸로 애플리케이션 코드가 프레임워크에 의해 사용됨
프레임워크 위에 개발한 클래스를 등록해두고 프레임워크가 흐름을 주도하는 중에 개발자가 만든 애플리케이션 코드를 사용하도록 만드는 방식

프레임워크에는 분명한 제어의 역전 개념이 적용되어 있어야 함
애플리케이션 코드는 프레임워크가 짜놓은 틀에서 수동적으로 동작해야 함

제어의 역전에서는 프레임워크 또는 컨테이너와 같이 애플리케이션 컴포넌트의 생성과 관계설정, 사용, 생명주기 관리 등을 관장하는 존재가 필요

DaoFactory는 오브젝트 수준의 가장 단순한 IoC 컨테이너 내지는 IoC 프레임워크라고 불릴 수 있음

IoC를 애플리케이션 전반에 걸쳐 본격적으로 적용하려면 스프링과 같은 IoC 프레임워크의 도움을 받는 편이 훨씬 유리함

 

스프링은 IoC를 모든 기능의 기초가 되는 기반기술로 삼고 있으며 IoC를 극한까지 적용하고 있는 프레임워크임