초난감 DAO v1
public class UserDao { public void add(User user) throws ClassNotFoundException, SQLException { Class.forName("com.mysql.cj.jdbc.Driver"); Connection c = DriverManager.getConnection("jdbc:mysql://localhost/springbook?characterEncoding=UTF-8", "spring", "book"); 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 id) throws ClassNotFoundException, SQLException { Class.forName("com.mysql.cj.jdbc.Driver"); Connection c = DriverManager.getConnection("jdbc:mysql://localhost/springbook?characterEncoding=UTF-8", "spring", "book"); PreparedStatement ps = c .prepareStatement("select * from users where id = ?"); ps.setString(1, id); 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; } }
위 코드가 끔찍한 이유
- add 메서드의 관심사를 살펴보면 크게 세 가지나 된다.
- DB conncetion 얻기
- sql 을 생성/실행하기
- 자원을 release 하고 connection 을 close 하기
- 예외 처리가 없다.
- 무책임하게 예외를 던져버린다. 그것도 기술의존적인 checked exception 을…
초난감 DAO 와 그를 사용하는 Client 의 클래스 다이어그램을 그리면 아래와 같다.

위 코드를 여러가지 객체지향의 무기를 사용해 개선해보자!
위의 여러 문제점 중 첫째 DB connection 을 얻는 방식을 분리해보자
1. private method 로 분리

- 좋은 변경이지만 만족 스럽지 않다.
UserDao
가 아닌ProductDao
가 등장한다면 같은 Connection 을 사용하더라도 privategetConnection
메서드가 중복되게 등장해야 한다.
- 결국 UserDao 의 커넥션을 결정할 책임은 아직 UserDao 가 가진다.
- 이래서는 Naver 와 Daum 에 우리의 UserDao 를 팔아먹을 수 없다!
2. 상속을 통한 확장

- 여전히 만족스럽지 않다.
- 역시 ProductDao 가 등장한다면?
- 각 Dao 마다 재정의를 위한 getConnection 메서드가 abstract 로 제공 되어야 하고 모든 자식 Dao 에서는 이를 재정의 해야한다.
- 엄청난 코드 중복이 발생한다.
- 상속을 사용했기 때문에 자식클래스와 부모클래스가 너무 관계가 깊다.
- 그에 반에 두 클래스의 책임이 너무 다르다.
- 자식 클래스는 커넥션의 생성만을, 부모 클래스는 이를 사용한 DB 처리를 책임진다.
3. 클래스의 분리

- 여전히 만족 스럽지 않다.
- 클래스만 분리 되었지 결국 UserDao 의 커넥션을 결정할 책임은 아직 UserDao 가 가진다.
- 이래서는 Naver 와 Daum 에 우리의 UserDao 를 팔아먹을 수 없다!
4. 인터페이스의 도입으로 의존도를 낮추기

- 훨씬 유연하다.
- 아주 훌륭하다.
여기서 얼렁 뚱땅 넘어가버린 것이 있다.
4 이전의
UserTest
는 원래 UserDao
를 사용해서 기능을 검증하는 역할만을 가졌었다.인터페이스를 도입하며 구체적인
Connection
, ConnectionMaker
를 설정하는 책임이 UserDao
의 바깥으로 분리되면서 자연스럽게 UserTest
가 이 책임까지 떠앉아 버렸다.이를 개선해보자