이 포스팅은 토비의 스프링을 읽고 개인적으로 정리하는 글입니다.
템플릿이란 바뀌는 성질이 다른 코드 중에서 변경이 거의 일어나지 않으며 일정한 패턴으로 유지되는 특성을 가진 부분을 자유롭게 변경되는 성질을 가진 부분으로부터 독립시켜서 효과적으로 활용할 수 있도록 하는 방법public void deleteAll() throws SQLException {
	Connection c =dataSource.getConnection();
    
	PreparedStatement ps =c.prepareStatement("delete from users");
	ps.executeUpdate();
	
	ps.close();
	c.close();
}.close()를 통해 자원을 반납하기 전에 예외가 발생하면 리소스가 정상적으로 반환되지 않을 수 있다. 이렇게 Pool에 있던 모든 리소스를 다 사용하고 반납하지 못하게 되면 리소스가 모자라다는 심각한 오류를 내며 서버가 중단될 수 있음.try-catch-finally문법을 사용하지만 현재는 <AutoCloseable> 인터페이스의 등장으로 인해 try-with-resources문법을 사용하는 것이 더 효율적이다)public void deleteAll() throws SQLException { 
	Connection c =null;
	PreparedStatement ps =null;
	try {
		rc =dataSource.getConnection();
		ps =c.prepareStatement("delete from users");
		ps.executeUpdate();
	} catch (SQLException e) { 
		throw e;
	} finally { 
		if (ps != null) { 
        	try {
				ps.close();
			} catch (SQLException e) { 
            }
        }
		if (c != null) { 
        	try {
				c.close(); 
            } catch (SQLException e) {
			}
		}
	}
}public int getCount() throws SQLException { 
	Connection c =null;
	PreparedStatement ps =null;
	ResultSet rs = null;
	try {
		c =dataSource.getConnection();
		ps = c.prepareStatement("select count(*) from users");
		rs.next();
		return rs.getInt(1);
	} catch (SQLException e) {
		throw e; 
    } finally {
		if (rs != null) { 
        	try {
				rs.close();
			} catch (SQLException e) { 
            }
        }
		if (ps != null) { 
        	try {
				ps .close();
			} catch (SQLException e) {
				if (c != null) { 
                	try {
						c. close();
					} catch (SQLException e) {
					}
				}
			}
		}
	}
}public void deleteAll() throws SQLException {
	...
	try {
		c =dataSource.getConnection();
		ps = makeStatement(c);
		ps.executeUpdate();
	} catch (SQLException e)
    ...
}
private PreparedStatement makeStatement(Connection c) throws SQLException { 
	PreparedStatement ps;
	ps = c.prepareStatement("delete from users");
	return ps;
}    public class UserDaoDeleteAll extends UserDao {
	protected PreparedStatement makeStatement(Connection c) throws SQLException { 
    	PreparedStatement ps = c.prepareStatement("delete from users");
		return ps;
	}
}템플릿 메소드 패턴보다 유연하고 확장성이 뛰어난 것이, 오브젝트를 아예 둘로 분리하고 클래스 레벨에서는 인터페이스를 통해서만 의존하도록 만드는 전략클라이언트가 전략을 생성해 전략을 실행할 컨텍스트에 주입하는 패턴UserDao는 이제 JdbcContext에 의존하고 있다. 하지만 이는 인터페이스가 아닌 구현체임.DI는 인터페이스를 두고 구현체를 여러개 만들어 바꿔 사용하는 것이 목적이었음
IoC의 개념을 포괄하고 있으므로 DI의 기본을 따르고 있다고 볼 수 있다.JdbcContext를 DI구조로 만들어야 할 이유JdbcContext가 스프링 컨테이너의 싱글톤 레지스트리에서 관리되는 싱글톤 빈이 되기 때문!JdbcContext가 DI를 통해 다른 빈에 의존하고 있기 때문!DI를 위해서는 양쪽 클래스 모두 빈으로 등록되어야 한다!UserDao와 JdbcContext가 매우 강하게 결합되어 있음.UserDao 내부에서 직접 DI를 적용하는 방법!JdbcContext를 갖고 있게 해야하기 때문이다.JdbcContext에 대한 제어권을 스프링이 아닌 사용자가 갖고 생성과 관리를 담당하는 UserDao에게 DI까지 맡기는 것!
UserDao와 StatementStrategy, JDbcContext를 이용해 만든 코드는 일종의 전략 패턴이 적용된 것!템플릿/콜백 패턴이라고 부른다.콜백은 실행되는 것을 목적으로 다른 오브젝트의 메소드에 전달되는 오브젝트를 말한다.
전략 패턴의 전략과 달리 템플릿 / 콜백 패턴의 콜백은 보통 단일 메소드 인터페이스를 사용한다. 이는 템플릿의 작업 흐름 중 특정 기능을 위해 한 번 호출되는 것이 일반적이기 때문이다.
템플릿 / 콜백 패턴에서는 매번 메소드 단위로 사용할 오브젝트를 새롭게 전달받는다는 것이 특징이며 또한 콜백 오브젝트가 내부 클래스로서 자신을 생성한 클라이언트 메소드 내의 정보를 직접 참조한다는 것도 고유한 특징이다.
executeSql() 메소드를 JdbcContext 내부로 옮겨 여러곳에서 사용할 수 있도록 수정한다.
템플릿 / 콜백 기능을 잘 사용할 수 있어야 한다.템플릿 / 콜백 패턴의 후보는 try/catch/finally 블록을 사용하는 코드다.템플릿/콜백은 스프링이 객체지향 설계와 프로그래밍에 얼마나 가치를 두고 있는지를 잘 보여주는 예다! 우리는 이를 잘 사용하는 것은 물론이고 필요하면 직접 만들어서 활용할 수도 있어야 한다!