개요
1. add() 메소드에도 전략 패턴 적용
2. 로컬 클래스와 내부 클래스
제목
1. add()메소드에도 전략 패턴 적용
deleteAll()메소드를 개선한 것과 같이 전략 패턴을 이용하여 add()메소드에도 적용해보자.
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;
}
}
deleteAll()과는 다르게 add()메소드에는 user라는 부가적인 정보가 필요하기 때문에 이를 생성자를 통해서 받을 수 있도록 설정한다. 위와 같이 수정함으로써 이제는 굳이 try/catch/finally로 범벅이된 중복 코드를 다룰 필요가 없게 되었다.
2. 로컬 클래스와 내부 클래스
다음으로 문제점으로 여기고 개선하고 싶은 부분은 DAO메소드마다 새로운 StatementStrategy구현 클래스를 만들어야 하기에 클래스의 수가 늘어난다는 점과 부가적인 정보가 있을 경우 오브젝트를 전달받기 위해서 생성자와 이를 저장해둘 변수를 번거롭게 만들어야 한다는 점이다.
클래스 파일이 많아지는 문제는 StatementStrategy를 굳이 외부 클래스로 선언하며 독립된 파일로 만들지 않고 내부 클래스로 정의하는 방법을 통해서 해결할 수 있다.
public void add(User user) throws SQLException{
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;
}
}
StatementStrategy st = new AddStatement(user);
jdbcContextWithStatementStrategy(st);
}
AddStatement클래스를 add()메소드 안에 집어넣은 것이다. 이를 통해서 독립된 클래스 파일이 늘어나는 문제를 개선할 수 있었다. 하지만 제기했던 두 번째 문제 User user변수를 만들고 생성자를 통해서 받도록 하는 것이 번거롭다는 문제는 여전히 남아있다. 이 문제는 내부 클래스에서 내부 클래스의 외부에 있는 메소드의 변수에 접근이 가능하다는 것을 이용하면 해결할 수 있다.
public void add(final User user) throws SQLException{//로컬 클래스에 final로 선언된 User 를 전달할 수 있다.
class AddStatement implements StatementStrategy{//로컬 클래스로 선언하여 클래스가 많아지는 문제 해결
@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;
}
}
StatementStrategy st = new AddStatement();//생성자 파라미터로 user를 전달하지 않아도 된다.
jdbcContextWithStatementStrategy(st);
}
add()메소드에서 받던 User user를 내부 클래스에서 사용할 수 있도록 final로 선언해주는 것으로 앞서 이야기 했던 변수 생성과 생성자를 통해 주입받는 코드를 작성하는 번거로움을 줄일 수 있게 되었다.
이 코드를 조금 더 간결하게 만들려면 이름을 붙이지 않아도 되는 익명 내부 클래스를 사용하면 된다. 수정하면 아래와 같이 만들 수 있다.
public void add(final User user) throws SQLException{//로컬 클래스에 final로 선언된 User 를 전달할 수 있다.
jdbcContextWithStatementStrategy(
new StatementStrategy() {//인터페이스를 생성자처럼 이용해서 익명 내부 클래스 생성
@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;
}
}
);
}
deleteAll()메소드도 위와 같이 정리해준다.
public void deleteAll() throws SQLException {
jdbcContextWithStatementStrategy(
new StatementStrategy() {//내부 익명 클래스
@Override
public PreparedStatement makePreparedStatement(Connection c) throws SQLException {
PreparedStatement ps = c.prepareStatement("delete from users");
return ps;
}
}
); //컨텍스트 호출 전략 오브젝트 전달
}
정리
1. 전략 패턴을 다른 메소드에도 적용해보고 내부 클래스를 이용하여 보다 간결한 코드를 만들 수 있게 되었다.
소스 정리 깃허브
cholongbul - Overview
만족할 수 있는 하루를 위해. cholongbul has 7 repositories available. Follow their code on GitHub.
github.com
'스프링' 카테고리의 다른 글
스프링 부트와 AWS로 혼자 구현하는 웹 서비스 따라하기 - 1 (0) | 2021.06.18 |
---|---|
토비의 스프링 - 3.4 컨텍스트와 DI (0) | 2021.06.18 |
토비의 스프링 - 3.1 다시보는 초난감 DAO // 3.2 변하는 것과 변하지 않는 것 (0) | 2021.05.31 |
토비의 스프링 - 2.4 스프링 테스트 적용 (0) | 2021.05.30 |
토비의 스프링 - 2.3 개발자를 위한 테스팅 프레임워크 JUnit (0) | 2021.05.28 |