[F-Lab 챌린지 33일차 TIL] 토비의 스프링 3장

성수데브리·2023년 7월 30일
0

f-lab_java

목록 보기
26/73

알고리즘

소수 판별 문제

  • 10만 이하에서 여러 숫자 비교할 경우 → 에라토스테네스 체 방식 에라토스테네스 체 : 주어진 숫자 범위에서 2의 배수, 3의 배수, 5의 배수, 7의 배수를 제거하고 남은 수가 소수다
  • 단순히 주어진 숫자가 소수인지 판별하거가 숫자가 제법 큰 경우 → 주어진 숫자의 제곱근까지 약수가 있는지만 확인

순열 in python

  • 순열이란 서로 다른 n 개 중 r 개를 골라 순서를 정해 나열하는 가짓수
  • 순서를 따지기 때문에 (a, b) 와 (b, a) 는 다른 것으로 본다.
arr = ['a', 'b', 'c']

for i in range(0, len(arr)):
    print(list(permutations(arr, i)))

[()]
[('a',), ('b',), ('c',)]
[('a', 'b'), ('a', 'c'), ('b', 'a'), ('b', 'c'), ('c', 'a'), ('c', 'b')]

공부 : 토비의 스프링 3,4,5장

  • 네거티브 테스트 : 예외상황에 대한 테스트를 하자. 정상적인 조건으로만 테스트 하지 말자
  • 예외상황에 대한 일관성 있는 기준을 정해두고 이를 테스트로 만들어 검증하자.

3장

전략 패턴 언제 적용하면 좋을까

바뀌지 않는 부분은 컨텍스트로, 바뀌는 부분은 전략으로

하나의 코드 뭉치에 변경되지 않는 부분과 변경 되는 부분의 경계가 뚜렷하면 변화의 특성이 다른 것이다.
자주 변경 되는 부분을 전략 객체로 분리하면 좋다.
자주 변하는 부분을 변하지 않는 부분과 독립적으로 변경될 수 있게 만드는 것이다.

전략 패턴을 적용하려면 자꾸 확장되고 자주 변하는 코드를 잘 분리해내야 한다.

  • 위 코드에서 file을 라인 단위로 읽고 IO 가 끝나면 자원들 닫는 코드는 자주 변경되지 않을 뿐더러
    여러곳에서 중복으로 사용될 것이다.
  • 반면 노란 박스 부분의 코드는 변경 또는 요구사항이 추가될 가능성이 높다.

템플릿/콜백 패턴으로 변경하면 코드는 아래와 같다.

[템플릿 메서드]

// 잘 변하지 않는 부분을 템플릿 역할을 하도록 메서드로 분리했다. 
public <T> T fileReaderTemplate(String filePath, BufferedReaderCallback<T> callback) throws IOException {

    BufferedReader br = null;
    try {
				// 자주 변경되는 부분을 전략 인터페이스로 분리하고 외부에서 전략 객체를 주입 받아 작업을 요청한다.
        return callback.doSomethingWithReader(new BufferedReader(new FileReader(filePath)));
    } catch (IOException e) {
        System.out.println(e.getMessage());
        throw e;
    } finally {
        if (br != null) {
            try {
                System.out.println("resource closed");
                br.close();
            } catch (IOException e) {
                System.out.println(e.getMessage());
            }
        }
    }
}

[전략 인터페이스]

// 전략 객체들의 인터페이스
public interface BufferedReaderCallback<T> {
    T doSomethingWithReader(BufferedReader bufferedReader) throws IOException;
}

[클라이언트 메서드]

public Integer calcSum(String filePath) throws IOException, NumberFormatException {
		// 템플릿 메서드를 호출하면서 전략 객체를 익명 내부 클래스로 전달하고 있다. 
    return fileReaderTemplate(filePath, new BufferedReaderCallback() {
        @Override
        public Integer doSomethingWithReader(BufferedReader br) throws IOException {
            Integer sum = 0;
            String line = null;
            while ((line = br.readLine()) != null) {
                sum += Integer.valueOf(line);
            }
            return sum;
        }
    });
}

템플릿/콜백 패턴

전략 패턴은 반복되는 코드에 특정 부분반 자주 바꿔서 사용해야 하는 경우에 적합한 구조다.
전략 객체를 인터페이스 구현클래스로 별도로 두지 않고 익명 내부 클래스를 활용한 방식을
템플릿/콜백 패턴이라고 부른다.

이때는 전략 패턴의 컨텍스트를 템플릿이라 부르고, 익명 내부 클래스로 만들어지는 오브젝트를 콜백이라 한다.
익명 내부 클래스의 로직을 파라미터 변수로 전달할 수 있다.

템플릿 내에서 콜백 함수를 중첩으로 호출할 수도 있으며 콜백 인터페이스를 제네릭 타입으로 변경해 재사용성을 증가시킬 수도 있다.
스프링은 이렇게 다양하게 템플릿/콜백 패턴을 응용해서 사용하고 있다.

JdbcTemplate

JdbTemplate 은 템플릿/콜백 패턴으로 구현된 클래스다

클라이언트에게 전달 받은 SQL 을 실행하고, 결과를 추출하고, 예외를 처리해준다.

PreparedStatementCreator : statement 를 생성하는 콜백 인터페이스다.

ResultSetExtractor : ResultSet 으로 부터 결과를 추출하는 콜백이다.


JdbTemplate 내부를 잠시 살펴보면 콜백을 통해 작업을 요청하고 결과값을 리턴한다.

sql 를 매개변수로 받아서 내부에서 QueryStatementCallback 콜백 객체를 생성해 execute() 로 넘긴다.
QueryStatementCallback 이 수행하는 작업은 쿼리 실행 후 실행 결과를 ResultSetExtractor 콜백에게 처리를 위임해 그 결과를 리턴한다.

커넥션을 취득하고 StatementCallback 에게 쿼리 수행을 요청하고 그 결과를 반환한다.

execute() 의 변하지 않는 부분은 커넥션을 취득하고 쿼리 수행 중 에러가 발생하면 예외 처리를 하는 것이다. 쿼리 수행 부분을 콜백에게 위임했다.

쿼리 수행, 쿼리 결과 처리 코드가 각각 StatementCallback, ResultSetExtractor 콜백 인터페이스로 분리되면서 언제든 변경과 확장이 가능해졌다.


StatementCallback 구현체만 보더라도 5개가 있다. execute() 메서드는 Statement 어떤 방식으로 처리 되는지 알 필요가 없고 작업 수행을 위한 커넥션 준비와 예외 발생시 예외 처리에만 집중할 수 있게 되었다.
코드를 변경하더라도 Statement 에는 영향이 가지 않는다.

0개의 댓글