ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 1.3.3 관계설정 책임의 분리
    책/토비의 스프링 2024. 7. 7. 16:10

    책을 읽고 흘려버리기 보단, 꼭꼭 씹어먹기 위해 정리해봅니다.

    이 포스팅은 이일민님의 <토비의 스프링3>에 기반하고 있습니다.


     

    1. 문제의 상황

    1) 클래스를 분리하였으나 여전히 UserDao가 특정 클래스의 이름에 대해 알아야함

     

     

    2. 해결방법

    클래스 간의 관계 -> 오브젝트 간의 관계로 변경

    현재 UserDao는 new NConnectionMaker()를 생성자에서 실행함으로써, 어떤 ConnectionMaker를 사용할지 결정하고 있다.

    UserDao와 ConnectionMaker의 관계를 UserDao 속에서 결정하는 것이 아닌 외부의 다른 객체에서 진행한다.

     

     

    3. 인터페이스와 의존성 주입을 통한 문제해결

    ConnectionMaker 인터페이스를 생성하여 고객사별로 구현을 하도록 만들고,

    UserDao는 ConnectionMaker 인터페이스를 구현한 객체를 주입받음으로 문제를 해결한다.

    더보기
    public interface ConnectionMaker {
      Connection getConnection() throws ClassNotFoundException, SQLException;
    }
    

     

    public class UserDao {
      private ConnectionMaker connectionMaker;
    
      public UserDao(ConnectionMaker connectionMaker) {
        this.connectionMaker = connectionMaker;
      }
      public void add(User user) throws SQLException, ClassNotFoundException {
        Connection c = connectionMaker.getConnection();
    
        PreparedStatement ps = c.prepareStatement("insert into users (id, name, password) values (?, ?, ?)");
        ps.setString(1, user.getId());
        ps.setString(2, user.getName());
        ps.setString(3, user.getPassword());
    
        ps.executeUpdate();
    
        ps.close();
        c.close();
      }
    
      public User get(String userId) throws SQLException, ClassNotFoundException {
        Connection c = connectionMaker.getConnection();
    
        PreparedStatement ps = c.prepareStatement("select * from users where id = ?");
        ps.setString(1, userId);
        ResultSet rs = ps.executeQuery();
        rs.next();
    
        User user = new User();
        user.setId(rs.getString("id"));
        user.setName(rs.getString("name"));
        user.setPassword(rs.getString("password"));
    
        rs.close();
        ps.close();
        c.close();
    
        return user;
      }
    
      public void deleteAll() throws ClassNotFoundException, SQLException {
        Connection c = connectionMaker.getConnection();
    
        PreparedStatement ps = c.prepareStatement("delete from users");
        ps.executeUpdate();
    
        ps.close();
        c.close();
      }
    
    }
    

     

    public class NConnectionMaker implements ConnectionMaker{
      public Connection getConnection() throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");
        Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3306/springbook", "root", "12345678");
        
        System.out.println("Do sth special for N");
    
        return c;
      }
    }
    

     

    public class UserDaoTest {
      public static void main(String[] args) throws SQLException, ClassNotFoundException {
        ConnectionMaker nConnectionMaker = new NConnectionMaker();
        UserDao dao = new UserDao(nConnectionMaker);
        dao.deleteAll();
    
        User user = new User();
        user.setId("a3_n283u2");
        user.setName("han");
        user.setPassword("1234");
    
        dao.add(user);
        System.out.println(user.getId() + " 등록 성공");
    
        User user2 = dao.get(user.getId());
        System.out.println(user2.getId() + " 조회 성공");
        System.out.println(user2.getId() + " 조회 성공");
    
      }
    }

     

     

    고객사별로 필요한 로직을 구현한다.

    // interface
    public interface ConnectionMaker {
      Connection getConnection() throws ClassNotFoundException, SQLException;
    }
    
    
    
    // N사를 위한 로직
    public class NConnectionMaker implements ConnectionMaker{
      public Connection getConnection() throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");
        Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3306/springbook", "root", "12345678");
    
        System.out.println("Do sth special for N");
    
        return c;
      }
    }
    
    // D사를 위한 로직
    public class DConnectionMaker implements ConnectionMaker{
      public Connection getConnection() throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");
        Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3306/springbook", "root", "12345678");
    
        System.out.println("Do sth special for D");
    
        return c;
      }
    }

     

     

    UserDao는 더 이상 사용해야하는 클래스 이름을 모르게 되고, 생성자의 인자로 전달되는 객체에 의존하게 된다 ( 클래스 관계 > 오브젝트 관계)

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

     

    UserDao가 어떤 객체를 사용하게 될지는 UserDao의 클라이언트에서 결정한다

    // N사의 커넥션을 사용하는 경우
    public class UserDaoTest {
      public static void main(String[] args) throws SQLException, ClassNotFoundException {
        ConnectionMaker nConnectionMaker = new NConnectionMaker();
        UserDao dao = new UserDao(nConnectionMaker);
    	
        ...
      }
    }
    
    
    // D사의 커넥션을 사용하는 경우
    public class UserDaoTest {
      public static void main(String[] args) throws SQLException, ClassNotFoundException {
        ConnectionMaker nConnectionMaker = new DConnectionMaker();
        UserDao dao = new UserDao(nConnectionMaker);
    	
        ...
      }
    }

     

     


    [출처]

    이일민님의 <토비의 스프링3>

    [이미지 출처]

    https://m.yes24.com/Goods/Detail/4020006

     

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

    1.4.1 오브젝트 팩토리  (0) 2024.07.08
    1.3.1 클래스의 분리  (0) 2024.07.07
    1.2.3 DB 커넥션 만들기의 독립  (0) 2024.07.07
    1.2.2 커넥션 만들기의 추출  (0) 2024.07.07
    1.1 초난감 DAO  (0) 2024.07.07
Designed by Tistory.