💡 문제 해결의 핵심은 변하지 않으며 많은 곳에서 중복되는 코드와 로직에 따라 확장되고 변하는 코드를 분리해내는 것이다.
deleteAll()
메소드와 구조의 거의 비슷할 것이다.deleteAll()
, add()
두 메서드에서 노란색 박스 안의 부분은 동일한 구조를 갖는다.deleteAll()
에서 가운데 부분만 수정하면 add()
를 만들 수 있다.⌨️ deleteAll()
⌨️ add()
개방 폐쇄 원칙 (OCP)을 잘 지키는 구조이면서도 유연하고 확장성이 뛰어나다.
public interface StatementStrategy {
PreparedStatement makePreparedStatement (Connection c) throws SQLException;
}
⌨️ DeleteAllStatement
public class DeleteAllStatement implements StatementStrategy{
@Override
public PreparedStatement makePreparedStatement(Connection c) throws SQLException {
PreparedStatement ps = c.prepareStatement("delete from Users");
return ps;
}
}
⌨️ AddStatement
public class AddStatement implements StatementStrategy{
User user;
public AddStatement(User user) {
this.user = user;
}
@Override
public PreparedStatement makePreparedStatement(Connection c) throws SQLException {
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());
return ps;
}
}
public void jdbcContextWithStatementStrategy(StatementStrategy stmt) throws SQLException {
Connection conn = null;
PreparedStatement ps = null;
try {
conn = connectionMaker.makeConnection();
ps = stmt.makePreparedStatement(conn);
ps.executeUpdate();
} catch (SQLIntegrityConstraintViolationException e) {
throw new SQLIntegrityConstraintViolationException(e);
} catch (SQLException e) {
throw e;
} finally {
if(ps != null){
try {
ps.close();
} catch (SQLException e) {
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
}
}
}
deleteAll()
은 전략 오브젝트를 만들고 컨텍스트를 호출하는 책임을 가지고 있다.public void deleteAll() throws SQLException {
jdbcContextWithStatementStrategy(new DeleteAllStatement());
}
add()
메소드는 user 정보를 생성자를 통해 전달해준다.public void add(User user) throws SQLException {
AddStatement addStatement = new AddStatement(user);
jdbcContextWithStatementStrategy(addStatement);
}
💡 비록 클라이언트와 컨텍스트는 클래스를 분리하지 않았지만, 의존관계과 책임으로 볼 때 이상적인 클라이언트/컨택스트 관계를 갖고 있다.
특히, 클라이언트가 컨택스트가 사용할 전략을 정해서 전달한다는 면에서 DI 구조라고도 할 수 있다.