3장 템플릿(1)

Soonwoo Kwon·2022년 2월 27일
0

토비의 스프링

목록 보기
3/11

3.1 다시 보는 초난감 DAO

예외 처리

try/catch/finally

  • try: 예외가 발생할 수 있는 코드
  • catch: 예외가 발생했을 때 부가적인 작업을 하기 위한 코드
  • finally: 예외 발생과는 별개로 반드시 실행되는 코드

3.2 변하는 것과 변하지 않는 것

try/catch/finally의 문제점

  • try/catch/finally가 제대로 작성되지 않으면 커넥션 리소스가 반환되지 않는 경우가 방생하게 된다.
  • 이렇게 리소스가 반환되지 않는 상황이 누적된다면 서버가 중단되게 된다.
  • 이 try/catch/finally 코드를 일일히 확인하는 것은 매우 번거로운 일이므로 분리해낼 필요가 있다.

분리와 재사용을 위한 디자인 패턴 적용

템플릿 메소드 패턴의 적용

  • 변하는 부분을 메소드 추출을 통해 얻어내도록 한다(makeStatement)
  • 이 메소드를 추상 메소드로 구현하고 해당 클래스도 추상 클래스로 구현한다.
  • 추상 클래스를 상속받아 기능에 따라 makeStatement 메소드를 구현하여 사용한다.
  • 추출해야 하는 메소드(기능)이 많을 경우 해당 메소드의 수 만큼 서브클래스를 구현해야하는 단점이 있다.

전략 패턴의 적용

  • 개방 폐쇄 원칙을 잘 지키도록 하기 위해 오브젝트를 컨텍스트와 전략으로 분리한다.
  • 컨텍스트는 전략과는 관계 없이 동일하게 동작하는 부분이다.
  • 전략은 기능마다 다르게 확장되는 부분으로 예시에서는 PreparedStatement를 생성해주는 기능이다.

DI 적용

  • 컨텍스트가 전략 클래스의 어떤 오브젝트가 사용됬는지 알고 있는것은 OCP에 어긋나므로 DI를 적용할 필요가 있다.
  • 클라이언트에서 전략을 생성하고 주입해주는 방법을 통해 컨텍스트는 어떤 전략 클래스의 오브젝트가 사용되는지 알 필요가 없게 된다.

3.3 JDBC 전략 패턴의 최적화

전략과 클라이언트의 동거

개선할 부분

  1. DAO 메소드 마다 새로운 StatementStrategy 구현 클래스를 생성해야 한다.
  2. DAO 메소드에서 StatementStrategy에 전달할 부가적인 정보가 있을 경우 번거롭게 인스턴스 변수를 생성해야 한다.

로컬 클래스

  • 전략 클래스를 매번 독립된 클래스 파일로 생성하지 않고 UserDao의 내부 클래스로 정의한다.
  • 전략 마다 많은 클래스 파일을 생성하지 않아도 된다.
  • 내부 클래스는 자신이 선언된 곳의 정보에 접근할 수 있기 때문에 부자적인 정보를 전달하기 위한 변수 생성을 하지 않아도 된다.

3.4 컨텍스트와 DI

JdbcContext의 분리

  • 현재 컨텍스트 메소드는 UserDao 내의 PreparedeStatement를 실행하기 위한 메소드이다.
  • 이 메소드를 다른 DAO에서도 사용할 수 있게 UserDao 클래스 밖으로 독립시킨다.

클래스 분리

  • JdbcContext 클래스를 생성하여 datasource에 의존하도록 한다.
  • workWithStatementStrategy를 통해 Stratey를 파라미터로 전달받는다.
  • UserDao는 private 변수 jdbcContext를 갖고 이 오브젝트를 이용한다.
  • JdbcContext는 추상 클래스가 아니라 일반적인 DI의 방법과는 다르지만, JdbcContext의 구현 방법이 바뀌지 않으므로 구체 클래스로 사용한다.

스프링 빈으로 DI

  • JdbcContetxt를 구체 클래스로 사용하지 않았지만, DI가 필요한 두 가지 이유가 있다.
    1. 싱글톤 레지스트리에서 관리되는 싱글톤 빈이 되기 위해서이다.
    2. JdbcContext가 다른 빈에(DataSource) 의존하고 있기 때문이다.
      • DI를 위해서는 주입과 관련된 양 쪽 오브젝트 모두 스프링 빈에 등록되어야한다.

3.5 템플릿과 콜백

템플릿

  • 어떤 목적을 위해 미리 만들어둔 틀
  • 전략 패턴의 컨텍스트를 의미한다.

콜백

  • 실행되는 것을 목적으로 다른 오브젝트의 메소드에 전될되는 오브젝트
  • 전략 패턴의 내부 클래스로 만들어지는 오브젝트를 의미한다.

3.6 스프링의 JdbcTemplate

update()

  • SQL 구문을 파라미터로 받아 실행하는 메소드이다.
  • 치환자를 가진 SQL 구문을 만들수 있으며 가변인자는 파라미터와 순서대로 바인딩되어 사용된다.

queryForInt()

  • Integer 타입의 결과를 가져오는 SQL 구문을 파라미터로 받아 사용한다.

queryObject()

  • SQL 구문과 Object[] 배열을 파라미터로 받아 사용한다.
  • queryForObject()의 파라미터 SQL을 실행하면 한 개의 로우만 얻을 것이라고 기대한다.
  • 로우의 개수가 하나가 아닌 경우 예외를(EmptyResultDataAccessException) 던지도록 만들어져있다.

query()

  • queryForObject() 와는 다르게 여러 개의 로우가 결과로 나오는 경우 사용한다.
  • 리턴 타입은 List<T>이다.
  • 첫 번째 파라미터는 실행할 SQL 쿼리이다.
  • 두 번째 파라미터는 바인딩할 파라미터이다.
  • 마지막 파라미터는 RowMapper 콜백이다.
    • RowMapper는 SQL 쿼리의 결과를 정해진 클래스 타입의 오브젝트에 매핑한다.

0개의 댓글