본문 바로가기

Spring/토비의 스프링 3.1

1.4 제어의 역전(IoC)


1.4.1 오브젝트 팩토리

기존 코드의 문제점

  1. 문제의 원인(UserDaoTest)
    • Test 수행 클래스
    • 어떤 ConnectionMaker 구현 클래스를 사용할지를 결정하는 역할까지 떠맡음(또 다른 책임)
  2. 해결책
    • 관심사의 분리
    • UserDao와 ConnectionMaker 구현 클래스의 오브젝트를 생성
    • 두 개의 오브젝트를 연결하여 사용될 수 있도록 관계를 맺어주는 클래스 필요

팩토리

팩토리(Factory)

  • 객체의 생성 방법을 결정하고, 그렇게 만들어진 오브젝트를 돌려주는 오브젝트
  • 오브젝트를 생성하는 쪽과 생성된 오브젝트를 사용하는 쪽의 역할과 책임을 분리하려는 목적

DaoFactory.class

  • UserDao, ConnectionMaker 생성작업
public class DaoFactory {
    /*
     * 팩토리의 메소드는 UserDao 타입의 오브젝트를
     * 어떻게 만들고, 어떻게 준비시킬지를 결정한다. 
     */
    public UserDao userDao() {
        ConnectionMaker connectionMaker = new DConnectionMaker();
        UserDao userDao = new UserDao(connectionMaker);
        return userDao;
    }
}

UserDaoTest.class

  • UserDaoTest는 DaoFactory에 요청해서 만들어진 UserDao 오브젝트를 가져와 사용함
public class UserDaoTest {
    public static void main(String[] args) throws ClassNotFoundException, SQLException{
        DaoFactory factory = new DaoFactory();
        UserDao dao = factory.userDao();
        // ...
    }
}

설계도로서의 팩토리

책임의 분리

  1. UserDao / ConnectionMaker
    • 데이터 로직 + 기술 로직
    • 실질적인 로직을 담당하는 컴포넌트
  2. DaoFactory
    • 애플리케이션의 오브젝트를 구성하고 관계를 정의
    • 컴포넌트의 구조와 관계를 정의한 설계도

DaoFactory는 소스를 제공함

  • N사와 D사는 Daofactory를 수정하여 사용 가능
  • 핵심 기술인 UserDao는 소스코드 보존 가능
  • DB 연결 방식은 자유로운 확장이 가능함

1.4.2 오브젝트 팩토리의 활용

현재 DaoFactory의 문제점

  • 관심은 분리가 되었으나 확장에 유연하지 못함
  • UserDao 외 다른 Dao 생성 기능이 생긴다면?
  • userDao() 메소드를 복사해서 만들게 되면 오브젝트 생성코드가 매번 반복됨
  • ConnectionMaker 구현 클래스가 변경되면 모두 다 바꿔주어야 함

중복으로 인한 문제점 예시

public class DaoFactory {
    public UserDao userDao() {
        // ConnectionMaker 구현 클래스를 선정하고 생성하는 코드의 중복
        ConnectionMaker connectionMaker = new DConnectionMaker();
        UserDao userDao = new UserDao(connectionMaker);
        return userDao;
    }
    public AccountDao accountDao() {
        // ConnectionMaker 구현 클래스를 선정하고 생성하는 코드의 중복
        ConnectionMaker connectionMaker = new DConnectionMaker();
        AccountDao accountDao = new AccountDao(connectionMaker);
        return accountDao;
    }
    public MessageDao messageDao() {
        // ConnectionMaker 구현 클래스를 선정하고 생성하는 코드의 중복
        ConnectionMaker connectionMaker = new DConnectionMaker();
        MessageDao messageDao = new MessageDao(connectionMaker);
        return messageDao;
    }
}

해결책 : 메소드 추출 기법

  • ConnectionMaker 구현 클래스를 선정하고 생성하는 코드를 별도의 메소드로 분리
  • Dao가 아무리 많아져도 해당 메소드만 수정하면 됨

수정된 DaoFactory.class

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

    /*
     * 분리해서 중복을 제거한 ConnectionMaker타입 오브젝트 생성 코
     */
    public ConnectionMaker connectionMaker() {
        return new DConnectionMaker();
    }
}

1.4.3 제어권의 이전을 통한 제어의 역전

제어의 역전

  • 제어의 역전 : 프로그램의 제어 흐름 구조가 뒤바뀌는 것
  • 일반적인 프로그램의 흐름
    1. main() 메소드 등 프로그램의 시작
    2. 다음에 사용할 오브젝트를 결정
    3. 결정한 오브젝트의 생성
    4. 만들어진 오브젝트의 메소드 호출
    5. 해당 오브젝트 메소드 내에서 다음에 사용할 것은 결정하고 호출
    6. 반복
  • 각 오브젝트는 프로그램의 흐름을 결정하거나 사용할 오브젝트를 구성하는 작업에 능동적으로 참여
  • 제어의 역전에서는 오브젝트가 자신이 사용할 오브젝트를 스스로 선택하지 않음
  • 모든 제어 권한을 다른 대상에게 위임
  • main() 등의 엔트리 포인트를 제외하면 모든 오브젝트는 위임받은 제어 권한을 갖는 특별한 오브젝에 의해 결정되고 만들어짐

UserDao와 DaoFactory

  • ConnectionMaker의 구현 클래스 결정 및 오브젝트 생성 제어권 : UserDao -> DaoFactory
  • UserDao, ConnectionMaker는 수동적인 존재로 바뀜
    1. UserDao, ConnectionMaker 자신도 DaoFactory에 의해 생성됨
    2. 자신이 사용할 오브젝트(ConnectionMaker)도 DaoFactory에게 공급받아 수동적으로 사용
  • DaoFactory : 가장 단순한 IoC 컨테이너 / IoC 프레임워크


' Spring > 토비의 스프링 3.1' 카테고리의 다른 글

1.6 싱글톤 레지스트리와 오브젝트 스코프  (0) 2019.01.09
1.5 스프링의 IoC  (0) 2019.01.07
1.3 DAO의 확장  (0) 2019.01.07
1.2 DAO의 분리  (0) 2019.01.03
1.1 초난감 DAO  (0) 2019.01.03