ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 1.3.1 클래스의 분리
    책/토비의 스프링 2024. 7. 7. 15:21

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

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


     

     

    1. 기존 방법의 문제점

    책에서는 여러 가지 이유로 상속의 문제점에 대해서 이야기하고 있습니다. 하지만 언급하는 대부분의 내용들이 추상메소드를 상속하는 경우에는 해결이 되는 부분이라고 느껴져서 크게 와닿지 않았습니다.

     

    특히 상속을 통한 상하위 클래스의 관계가 밀접하여 superclass를 변경할 경우 모든 서브클래스를 변경해야할 수 있다는 부분이있는데, 이 부분은 superclass 메소드의 시그니쳐가 바뀌지 않는한 subclass에서 변경을 신경쓸 필요가 없다고 생각이 듭니다. 만약 메소드의 시그니쳐가 바뀌는 경우라면, 인터페이스를 사용해도 동일한 부작용을 가져올 것이기 때문에 상속만의 문제는 아니라고 생각됩니다.

     

    확실하게 와닿는 문제는 자바에서는 다중 상속을 지원하지 않기 때문에, 다른 superclass를 상속받을 수 없는 상황이 생기거나 기존에 상속받고 있는 superclass가 있다면 UserDao를 적용할 수 있다는 점이었습니다.

     

     

    2. 해결방법

    상속이 여러가지 문제를 야기하기 때문에, 별도의 클래스로 분리하는 방법을 사용합니다.

     

     

    3. 클래스 분리를 사용한 문제 해결

    SimpleConnectionMaker라는 데이터베이스 커넥션을 관리하는 별도의 클래스를 만들고 상속을 제거하였습니다.

    상속을 제거하였기때문에 상속으로 인해 발생하는 문제를은 해결이되었습니다.

     

    하지만 다시 문제가 원점으로 돌아왔습니다?

    개별 고객사를 위한 커스터마이징을 할 수 없는 상태가 되었습니다.

    더보기
    // SimpleConnectionMaker.java
    public class SimpleConnectionMaker {
      public Connection getConnection() throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");
        Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3306/springbook", "root", "12345678");
    
        return c;
      }
    }
    
    
    
    // UserDao.java
    public class UserDao {
      private SimpleConnectionMaker simpleConnectionMaker;
      
      public UserDao() {
        this.simpleConnectionMaker = new SimpleConnectionMaker();
      }
      public void add(User user) throws SQLException, ClassNotFoundException {
        Connection c = simpleConnectionMaker.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 = simpleConnectionMaker.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 = simpleConnectionMaker.getConnection();
    
        PreparedStatement ps = c.prepareStatement("delete from users");
        ps.executeUpdate();
    
        ps.close();
        c.close();
      }
      
    }
    
    // UserDaoTest.java
    public class UserDaoTest {
      public static void main(String[] args) throws SQLException, ClassNotFoundException {
        UserDao dao = new UserDao();
        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() + " 조회 성공");
    
      }
    }

     

     

    개별 고객사의 요구사항을 반영하려면, 회사별로 ConnectionMaker를 생성해서 사용해야하게 되었습니다.

    // NConnectionMaker.java
    public class NConnectionMaker {
      public Connection getConnection() throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");
        Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3306/springbook", "root", "12345678");
    
        return c;
      }
    }
    
    
    
    // UserDao.java
    public class UserDao {
      private NConnectionMaker nconnectionMaker;
      
      public UserDao() {
      	this.nconnectionMaker = new NConnectionMaker()  
      }
      
      ...
     }

     

     

    DB 커넥션 방법을 변경하기 위해서는 UserDao의 소스코드를 변경해야하는 아주 나쁜 상태입니다.

    이는 UserDao가 DB 커넥션을 가져오는 클래스에 대해 너무 많이 알고 있기 때문에 발생합니다. 

    가져오는 이름도 알아야하고, 사용해야하는 메소드도 알아야하기 때문에 소스코드가 변경되는 상황이 발생합니다.

     


    [출처]

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

    [이미지 출처]

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

     

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

    1.4.1 오브젝트 팩토리  (0) 2024.07.08
    1.3.3 관계설정 책임의 분리  (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.