본문 바로가기

스터디/토비의 스프링 3.1

[토비의 스프링] 1-4. IoC 제어의 역전

1장 오브젝트와 의존관계

==사전 준비==

UserVo 클래스

package com.cafe24.vo;

public class UserVo {

    private String id;
    private String name;
    private String password;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "UserVo [id=" + id + ", name=" + name + ", password=" + password + "]";
    }
}

UserDao 클래스

package com.cafe24.dao;

public class UserDao {

    private ConnectionMaker connectionMaker;

    public UserDao() {
        connectionMaker = new DConnectionMaker();
    }

    public UserDao(ConnectionMaker connectionMaker) {
        this.connectionMaker = connectionMaker;
    }

}

ConnectionMaker 인터페이스

package com.cafe24.dao;

import java.sql.SQLException;

import com.cafe24.vo.UserVo;

public interface ConnectionMaker {

    public ConnectionMaker makeConnection() throws ClassNotFoundException, SQLException;

    public void add(UserVo userVo) throws ClassNotFoundException, SQLException;

    public void get(String id) throws ClassNotFoundException, SQLException;
}

DConnectionMaker 클래스

package com.cafe24.dao;

import java.sql.SQLException;

import com.cafe24.vo.UserVo;

public class DConnectionMaker implements ConnectionMaker {

    /* ConnectionMaker를 가져와 makeConnection() 메소드를 구체적으로 구현한다. */
    public ConnectionMaker makeConnection() throws ClassNotFoundException, SQLException {

        return null;
    }

    public void add(UserVo userVo) throws ClassNotFoundException, SQLException {
        // TODO Auto-generated method stub

    }

    public void get(String id) throws ClassNotFoundException, SQLException {
        // TODO Auto-generated method stub

    }

}

DaoFactory 클래스

package com.cafe24.dao;

public class DaoFactory {

    /* UserDao 클래스와 ConnectionMaker 인터페이스의 독립된 관계 형성을 위한 팩토리 클래스*/
    public UserDao userDao() {
        ConnectionMaker connectionMaker = new DConnectionMaker();
        UserDao userDao = new UserDao(connectionMaker);
        return userDao;
    }
}

일반적으로 프로그램의 흐름은 main() 메소드와 같이 프로그램이 시작되는 지점에서 다음에 사용할 오브젝트를 결정하고 오브젝트를 생성하고 만들어진 오브젝트의 메소드를 호출하는 식의 작업이 반복된다.

우리가 처음 만들었던 UserDao의 경우에도 connection을 직접 생성하고 연결을 하여 자신이 사용할 클래스를 결정하고 사용하여 제어하는 구조이다.

하지만 앞으로 이야기할 제어의 역전(IoC)는 제어권을 다른 대상에게 위임하여 자신이 사용할 오브젝트를 결정하지 않고 생성하지도 않는다.

1.4 제어의 역전(IoC)

오브젝트 팩토리의 활용

DaoFactory 클래스

package com.cafe24.dao;

public class DaoFactory {

    /* UserDao 클래스와 ConnectionMaker 인터페이스의 독립된 관계 형성을 위한 팩토리 클래스*/
    public UserDao userDao() {
        ConnectionMaker connectionMaker = new DConnectionMaker();
        UserDao userDao = new UserDao(connectionMaker);
        return userDao;
    }
}

DaoFactory 클래스에서 핵심 기능인 UserDao 클래스와 ConnectionMaker 가 연결이 되었다. DaoFactory에 의해 각 핵심기능이 독립된 관계를 형성하여 UserDao의 소스코드를 건드리지 않을 수 있게 되었으며 ConnectionMaker의 상속을 받은 클래스도 DaoFactory에서 변경이 가능하게 되었다. 따라서 우리는 DaoFactory의 수정으로 어느 환경에서든 연결이 가능한 상태로 만들었다. 즉, 제어권이 역전되어 UserDao에서 connectionMaker를 결정할 권한을 DaoFactory로 넘기게 되었으며 DaoFactory에서 결정이 되는 것을 수동적으로 UserDao가 사용해야 한다.

단, 만일 UserDao 외에도 BoardDao, GuestbookDao 등의 새로운 DAO가 생긴다면 동일한 ConnectionMaker 오브젝트 생성 코드를 각각의 DAO 메소드 내에 구현을 해야한다. 이러한 중복은 피하는 것이 좋으며 분리하는 방법이 있다. 따라서 중복이 되는 코드를 별도의 메소드로 뽑아내보자.

DaoFactory 클래스(connectionMaker 중복제거)

package com.cafe24.dao;

public class DaoFactory {

    /* UserDao 클래스와 ConnectionMaker 인터페이스의 독립된 관계 형성을 위한 팩토리 클래스*/
    public UserDao userDao() {
        return new UserDao(connectionMaker());
    }

    public BoardDao BoardDao() {
        return new BoardDao(connectionMaker());
    }

    public GuestbookDao GuestbookDao() {
        return new GuestbookDao(connectionMaker());
    }

    public ConnectionMaker connectionMaker() {
        return new DConnectionMaker();
    }
}