1. 오브젝트와 의존관계 - IoC


1.4 제어의 역전(IoC)

IoC는 Inversion of Conrol (제어의 역전)의 약자이다.

1.4.1 오브젝트 팩토리

현재 UserDao의 클라이언트 오브젝트인 main은 2개의 관심사를 갖고 있다.

  • UserDao와 ConnectionMaker 구현 클래스의 오브젝트를 만드는 것
  • 그렇게 만들어진 두 개의 오브젝트가 런타임 시점에 연결돼서 사용(테스트)되는 것

위 2개의 관심사 까지 분리해보도록 하겠다.

factory (팩토리)

정의

  • 객체의 생성 방법을 결정하고 그렇게 만들어진 오브젝트를 돌려주는 역할을 하는 오브젝트

    디자인 패턴에서의 팩토리 메소드 패턴이나 추상 팩토리 패턴과는 다른 개념이다.

사용 목적

  • 아래의 역할과 책임을 2가지 오브젝트로 나눔
    - 오브젝트를 생성 (DaoFactory)
    • 생성된 오브젝트를 사용 (main)

UserDao의 생성 책임을 맡은 팩토리 클래스

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

        return userDao;
    }
}

팩토리를 사용하도록 수정한 main

public class main {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {

        UserDao userDao = new DaoFactory().userDao();
        
        ...
	}
}

설계도로서의 팩토리

  • 컴포넌트 : UserDao 와 ConnectionMaker와 같이 실질적인 로직을 담당하는 부분
  • 설계도 : 애플리케이션을 구성하는 컴포넌트의 구조와 관계를 정의

1.4.2 오브젝트 팩토리의 활용

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

DaoFactory에 AccountDao, MessageDao 등을 만듦

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

        return userDao;
    }

    public AccountDao accountDao() {
        ConnectionMaker connectionMaker = new DConnectionMaker();
        AccountDao accountDao = new AccountDao(connectionMaker);

        return accountDao;
    }

    public MessageDao messageDao() {
        ConnectionMaker connectionMaker = new DConnectionMaker();
        MessageDao messageDao = new MessageDao(connectionMaker);

        return messageDao;
    }
}

문제점
3개의 메소드에 ConnectionMaker 구현 클래스를 선정하고 생성하는 코드의 중복이 발생한다.

해결법
중복이 발생하는 ConnectionMaker 구현 클래스를 선정하고 생성하는 코드를 별도의 메소드로 뽑아낸다.

public class DaoFactory {
    public UserDao userDao() {
        UserDao userDao = new UserDao(connectionMaker());

        return userDao;
    }

    public AccountDao accountDao() {
        AccountDao accountDao = new AccountDao(connectionMaker());

        return accountDao;
    }

    public MessageDao messageDao() {
        MessageDao messageDao = new MessageDao(connectionMaker());

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

효과

  • 아무리 DAO 종류가 다야해져도 문제가 없다.
  • ConnectionMaker의 구현 클래스가 변경되어도 connectionMaker( ) 메소드 코드를 한번만 변경해주면 된다.

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

오브젝트(Client)는 자신이 사용할 오브젝트를 스스로 선택하지도, 생성하지도 않는다.
모든 제어 권한은 다른 특별한 오브젝트(설계도)에게 위임되어 있다.

  • UserDao가 어떤 ConnectionMaker의 구현 클래스를 사용할지는 DaoFactory에 의해 정해진다.

  • main은 DaoFactory가 만들고 초기화하여 리턴해주는 dao만 사용할 수 있다.

IoC활용의 장점

  • 설계가 깔끔해진다.
  • 유연성이 증가한다.
  • 확장성이 좋아진다.

IoC는 프레임워크 없이도 단순 코드 설계만으로도 사용가능하다.
스프링 프레임워크는 이러한 IoC를 극한까지 적용하는 프레임워크이다.

소스코드 : github

좋은 웹페이지 즐겨찾기