이제 상속을 통한 DAO 확장을 해보자.
UserDao 소스코드를 N사와 D 사에 변경해서 제공해주지 않고도 고객 스스로 원하는 DB 커넥션 생성 방식을 적용하도록 해보도록 하겠다.
그 방법으로 UserDao 에서 getConnection() 메소드를 추상 메소드로 만들면 된다. 그렇다면 N사와 D사에서는 getConnection() 메소드를 자신들이 원하는 방법으로 구현을 한다면 다른 기존의 코드를 변경하지 않고 해당 메소드만 구현하면서 사용할 수 있을 것이다.
/* 상속을 통한 확장 방법이 제공되는 UserDao 클래스 */
public abstract class UserDao {
public void add(User user) throws ClassNotFoundException, SQLException {
Connection connection = getConnection();
PreparedStatement ps = connection.prepareStatement(
"INSERT INTO users(id, name, password) values(?, ?, ?)");
ps.setString(1, user.getId());
ps.setString(2, user.getName());
ps.setString(3, user.getPassword());
ps.executeQuery();
ps.close();
connection.close();
}
public User get(String id) throws ClassNotFoundException, SQLException {
Connection connection = getConnection();
PreparedStatement ps = connection.prepareStatement(
"SELECT * FROM users WHERE id = ?"
);
ps.setString(1, id);
ResultSet resultSet = ps.executeQuery();
resultSet.next();
User user = new User();
user.setId(resultSet.getString("id"));
user.setName(resultSet.getString("name"));
user.setPassword(resultSet.getString("password"));
resultSet.close();
ps.close();
connection.close();
return user;
}
public abstract Connection getConnection() throws ClassNotFoundException, SQLException;
}
이렇게 abstract 클래스로 변경 후 getConnection() 을 추상 메소드로 변경을 하였다. 그리고 이제 이 getConnection() 메소드를 구현할 클래스를 만들어보도록 하겠다.
/* 상속을 통한 D사의 getConnection() 메소드 구현 (껍데기) */
public class DUserDao extends UserDao {
public Connection getConnection() throws ClassNotFoundException, SQLException {
return null;
}
}
/* 상속을 통한 N사의 getConnection() 메소드 구현 (껍데기) */
public class NUserDao extends UserDao {
public Connection getConnection() throws ClassNotFoundException, SQLException {
return null;
}
}
이런 클래스 계층구조를 통해 두 개의 관심이 독립적으로 분리되면서 변경 작업이 쉬워졌다. 이런 식으로 코드를 짜면 UserDao 클래스의 코드는 한 줄도 수정할 필요가 없어진다.
이렇게 슈퍼 클래스에 기본적인 로직의 흐름을 만들고, 그 기능의 일부를 추상 메소드나 오버라이딩이 가능한 protected 메소드 등으로 만든 뒤 서브 클래스에서 구현해 사용하도록 하는 방법을 템플릿 메소드 패턴 이라고 한다.
상속을 사용해 생긴 단점이 있다. 만약 UserDao 클래스가 다른 목적을 위해 상속을 사용하고 있다면 위와 같이 상속을 못한다는 단점이 있다. 또한, 서브 클래스가 슈퍼 클래스의 기능을 직접 사용할 수 있기 때문에 슈퍼 클래스 내부에 변경이 있을 때 모든 서브 클래스를 수정하거나 다시 개발해야 할 수도 있다.
다음 장에서는 DB 커넥션과 관련된 부분을 서브 클래스가 아니라 아예 별도의 클래스에 담도록 하는 것을 이야기 하도록 하겠다~