3장 템플릿
개방 폐쇄 원칙: 확장에는 자유롭게 열려 있고 변경에는 굳게 닫혀있다.
템플릿 : 바뀌는 성질이 다른 코드 중에서 변경이 거의 일어나지 않으며
일정한 패턴으로 유지되는 특성을 가진 부분을
자유롭게 변경되는 성질을 가진 부분으로부터 독립시켜서
효과적으로 활용할 수 있는 방법이다.
분리와 재사용을 위한 디자인 패턴 적용
내부 클래스
클래스 분리와 DI
템플릿과 콜백
정리
예외처리
예외처리 필요성 : 예외가 발생했을 경우에도 사용한 리소스를 반드시 반환해야 한다.
- try/catch/finally
코드의 복잡도가 너무 높다.
모든 메소드마다 반복된다.
분리와 재사용을 위한 디자인 패턴 적용
- 변하는 부분을 변하지 않는 나머지 코드에서 분리
변하는 부분 : 쿼리 수행
변하지 않는 부분 : try/catch/finally
로 감싼 부분
방법 1. 메소드 추출
- 변하는 부분을 메소드로 추출한다.
문제 : 분리된 메소드가 재사용 되어야 하는데, 변하지 않는 남은 메소드가 재사용(반복)되고, 변하는 부분인 분리된 메소드는 재사용이 안 되고 매번 새롭게 만들어야 함
방법 2. 템플릿 메소드 패턴 적용
- 상속을 통해 기능을 확장해서 사용한다.
- 변하지 않는 부분(슈퍼클래스), 변하는 부분(추상클래스) 정의
- 서브클래스에서 오버라이드 하여 새롭게 정의해 사용
문제 : DAO 로직마다 상속을 통해 새로운 클래스 만들어야 함
확장구조가 이미 클래스를 설계하는 시점에 고정됨 -> 컴파일 시점에 관계 결정, 유연성 떨어짐
방법 3. 전략 패턴 적용
- 오브젝트를 아예 둘로 분리, 클래스 레벨에서는 인터페이스 통해서만 의존
- 변하는 부분을 별도의 클래스로 만들어, 추상화된 인터페이스를 통해 위임
- 변하는 부분 전략, 변하지 않는 부분 컨텍스트
문제 : 전략 패턴은 필요에 따라 컨텍스트는 그대로 유지(OCP폐쇄원칙), 전략은 바꿔 쓸 수 있음(OCP 페쇄원칙)
컨텍스트 안에서 구체적인 전략 클래스인 DeleteAllStatment
사용하면, 인터페이스 뿐만 아니라 특정 구현 클래스를 직접 알고 있음으로 전략패턴, OCP에 들어맞지 않음
DI 적용을 위한 클라이언트/컨텍스트 분리
- 컨텍스트를 사용하는 Client가 전략을 결정해야 함
- 클라이언트가 하나의 전략을 오브젝트로 만들어서 컨텍스트에 전달
내부 클래스
로컬 클래스
위 코드의 문제
- DAO메소드마다 새로운
StatementStrategy
구현 클래스 만들어야 함 - DAO메소드에서 전달할 부가 정보 있는 경우, 이를 위해 오브젝트를 전달받는 생성자와 저장해둘 인스턴스 변수 만들어야 함
해결
특정 메서드에서만 사용되는 전략 클래스를 UserDao
안에 내부 클래스로 정의
장점 : 로컬 클래스는 내부 클래스이기 때문에 자신이 선언된 곳의 정보에 접근 가능
-> 번거롭게 생성자를 통해 User 오브젝트 전달하지 않아도 됨
익명 내부 클래스
- 선언과 동시에 오브젝트 생성
- 사용하면 클래스 이름도 제거 가능
- 클래스 밖 변수는 final 붙어 있어야 사용 가능
클래스 분리와 DI
전략 패턴 구조UserDao
메소드 : 클라이언트
익명 내부 클래스 : 개별 전략 jdbcContextWithStatmentStrategy()
메소드 : 컨텍스트
jdbcContextWithStatmentStrategy()
다른 UserDao 밖으로 독립시켜 다른 DAO에서도 사용 가능하게 만들자
클래스 분리
- JDBC 작업 흐름을 분리하여
JdbcContext
클래스 만듦
전UserDao
-> DataSource
후UserDao
-> JdbcContext
-> DataSource
- UserDao에서는 커넥션 말고 쿼리를 작성하고 실행만 함
- JdbcContext가 DataSource에 의존하고 있으므로, DataSource 타입 빈을 DI 받을 수 있게 해야 함
스프링 DI는 인터페이스 사이에 두고 의존 클래스 바꿔서 사용하는 게 목족
JdbcContext는 구체클래스, DataSource 인터페이스
인터페이스를 두지 않아도 괜찮을까?
- 스프링의 DI는 넓게 보자면 객체의 생성과 관계설정에 대한 제어권한을 오브젝트에서 제거하고 외부로 위임했다는 IoC 개념 포괄
JdbcContext
를 스프링을 이용해UserDao
객체에서 사용하게 주입했다는 건 DI 의 기본
DI 구조로 만든 이유
JdbcContext
가 싱글톤으로 등록돼서 여러 오브젝트에서 공유해 사용될 수 있음JdbcContext
가 DI를 통해 다른 빈에 의존하고 있기 때문이다.DataSource
오브젝트 주입 받음, DI를 위해서는 주입되는,하는 오브젝트 양쪽이 스프링 빈으로 등록되어야 함- 스프링이 생성하고 관리하는 IoC 대상이어야 DI에 참여 가능
스프링 DI
장점 : 오브젝트의 의존관계가 설정파일에 명확하게 드러남
단점 : 구체적인 클래스와의 관계 직접 노출
수동 DI
장점 : 관계와 DI 전략 외부에 노출 X
단점 : 싱글톤으로 못만듦
템플릿과 콜백
템플릿 : 전략패턴의 컨텍스트 (변하지 않는 부분)
콜백 : 익명 내부 클래스로 만들어지는 오브젝트(변하는 부분)
메소드 레벨에서 일어나는 DI
- 클라이언트가 템플릿 메소드를 호출하면서 콜백 오브젝트를 전달하는 것
템플릿/콜백 패턴 특징
- 매번 메소드 단위로 사용할 오브젝트를 새롭게 전달받음
- 콜백 오브젝트가 내부 클래스로서 자신을 생성한 클라이언트 메소드 내의 정보 직접 참조
- 클라이언트와 콜백이 강하게 결합
일반 DI
- 템플릿에 인스턴스 변수 만들어두고 사용할 의존 오브젝트를 수정자 메소드로 받아서 사용
정리
- 일정한 작업 흐름이 반복되면서, 일부 기능만 바뀌면 바뀌지 않는 부분 컨텍스트, 바뀌는 부분 전략으로 만들어 인터페이스를 통해 전략을 변경할 수 있도록 전략패턴 적용하여 구성
- 여러 가지 전략 사용해야 하면, 컨텍스트 이용하는 클라이언트가 직접 전략 정의하고 제공
- 클라이언트 메소드 안에 익명 내부 클래스 사용하여 전략 오브젝트 구현하면 코드 간결, 메소드 정보 직접 사용할 수 있어 편리
- 컨텍스트가 하나 이상의 클라이언트 오브젝트에서 사용되면 클래스 분리해서 공유함
- 컨텍스트는 빈으로 등록해서 DI 받거나, 수동으로 DI 하는 두 가지 방법
- 템플릿/콜백 패턴은 컨텍스트 호출과 동시에 전략 DI를 수행하는 방식
- 콜백 코드에도 일정한 패턴 반복되면 콜백을 템플릿에 넣고 재활용 함
'토비의스프링vol.1' 카테고리의 다른 글
[토비의 스프링vol.1 6장] AOP - 1 (0) | 2023.04.03 |
---|---|
[토비의 스프링vol.1 5장] 서비스 추상화 (0) | 2023.04.03 |
[토비의 스프링vol.1 4장] 예외처리 (0) | 2023.04.03 |
[토비의 스프링vol.1 2장] 테스트 (0) | 2022.10.07 |
[토비의 스프링vol.1 1장] 오브젝트와 의존관계 (0) | 2022.10.03 |