Today I Learned_230704

2 분 소요

토비의 스프링 3.1

executeSql은 UserDao말고 다른 Dao 클래스에서도 사용성이 높아 보인다 → 템플릿 클래스로 빼자

// JdbcContext
    public void executeSql(final String query) throws SQLException {
        this.workWithStatementStrategy(
                new StatementStrategy() {
                    public PreparedStatement makePreparedStatement(Connection c) throws SQLException {
                        return c.prepareStatement(query);
                    }
                }
        );
    }

// UserDao의 deleteAll
private void deleteAll() throws SQLException {
        this.jdbcContext.executeSql("delete from users");
    }

→ JdbcContext 안에 클라이언트(executeSql), 템플릿(workWithStatementStrategy), 콜백(익명 내부 클래스)이 모두 함께 공존하면서 동작하는 구조

일반적으로 성격이 다른 코드들은 가능한 한 분리하는 편이 낫지만, 이 경우 하나의 목적을 위해 서로 긴밀하게 연관되어 동작하는 응집력이 강한 코드들이므로 모여 있는 것이 유리하다.

구체적인 구현, 내부의 전략 패턴, 코드에 의한 DI, 익명 내부 클래스 등의 기술은 최대한 감춰두고, 외부에는 꼭 필요한 기능을 제공하는 단순 메소드만 노출한다.

템플릿/콜백의 응용

템플릿/콜백은 스프링만의 기술은 아니지만, 스프링을 잘 활용하려면 스프링에서 제공하는 템플릿/콜백 기능을 잘 사용할 수 있어야 한다.

언제 템플릿/콜백 패턴을 사용할 수 있을지?

→ 고정된 작업 흐름(컨텍스트)을 갖고 반복되는 코드(템플릿)가 있다면 중복되는 코드를 분리하자.

중복 코드는 우선 메소드로 분리 → 전략 패턴 적용하여 DI로 의존관계 관리

→ 바뀌는 부분이 한 애플리케이션에서 동시에 여러 종류로 만들어진다 → 템플릿/콜백 패턴

try/catch/finally가 반복되면 템플릿/콜백 패턴을 적용해 볼 수 있다.

try/catch를 템플릿/콜백 패턴으로 바꿔보기

예시 코드

package com.example.demo3.learningtest.template;

import org.junit.Test;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
import java.io.IOException;

public class CalcSumTest {
    @Test
    public void sumOfNumbers() throws IOException {
        Calculator calculator = new Calculator();
        int sum = calculator.calcSum("numbers.txt");
        assertThat(sum, is(10));
    }
}

try-catch가 포함된 Calculator → 덧셈 기능을 하는 calcSum이 있는데 try-catch가 너무 많다.

package com.example.demo3.learningtest.template;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class Calculator {
    public Integer calcSum(String filepath) throws IOException {
        BufferedReader br = null;

        try {
            br = new BufferedReader(new FileReader(filepath));
            Integer sum = 0;
            String line = null;
            while((line = br.readLine()) != null) {
                sum += Integer.parseInt(line);
            }
            br.close();
            return sum;
        }
        catch (Exception e) {
            System.out.println(e.getMessage());
            throw e;
        }
        finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    System.out.println(e.getMessage());
                }
            }
        }
    }
}

곱하기 기능을 넣으려면 이 모든 try-catch를 복사/붙여넣기 해야 하는데 너무 귀찮을 것 같다!

→ 템플릿/콜백 패턴을 적용해 보자.

// 템플릿/콜백을 적용한 메소드
    public Integer calcSum(String filepath) throws IOException {
        return fileReadTemplate(filepath, new BufferedReaderCallback() {
            @Override //공통되지 않은 부분을 뺐다
            public Integer doSomethingWithReader(BufferedReader br) throws IOException {
                Integer sum = 0;
                String line = null;
                while((line = br.readLine()) != null) {
                    sum += Integer.parseInt(line);
                }
                return sum;
            }
        });
    }

    // 템플릿 메소드
    public Integer fileReadTemplate(String filepath, BufferedReaderCallback callback) throws IOException {
        BufferedReader br = null;

        try {
            br = new BufferedReader(new FileReader(filepath));
            int ret = callback.doSomethingWithReader(br); // 파라미터를 담아 콜백 오브젝트를 호출하고, 콜백의 작업 결과를 받아둔다
            br.close();
            return ret;
        }
        catch (Exception e) {
            System.out.println(e.getMessage());
            throw e;
        }
        finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    System.out.println(e.getMessage());
                }
            }
        }
    }

곱셈을 구하는 메소드를 구현하려면 calSum에서 익명 메소드 부분을 수정하면 된다.

카테고리:

업데이트: