템플릿 메서드 패턴 (Template Method Pattern)

반응형
728x90
반응형
수강완료한 강의 복습해보자
(코딩으로 학습하는 GoF의 디자인 패턴)


템플릿 메서드 (Factory method)

  • 알고리즘 구조를 서브 클래스가 확장할 수 있도록 템플릿으로 제공하는 방법.
  • 추상 클래스는 템플릿을 제공하고 하위 클래스는 구체적인 알고리즘을 제공한다.

 

 

적용 전 코드 (Before)

FileProcessor.java
public class FileProcessor {

    private String path;
    public FileProcessor(String path) {
        this.path = path;
    }

    public int process() {
        try(BufferedReader reader = new BufferedReader(new FileReader(path))) { // 자동 close
            int result = 0;
            String line = null;
            while((line = reader.readLine()) != null) {
                result += Integer.parseInt(line);
            }
            return result;
        } catch (IOException e) {
            throw new IllegalArgumentException(path + "에 해당하는 파일이 없습니다.", e);
        }
    }
}

 

MultiplyFileProcessor.java
public class MultiplyFileProcessor {

    private String path;
    public MultuplyFileProcessor(String path) {
        this.path = path;
    }

    public int process() {
        try(BufferedReader reader = new BufferedReader(new FileReader(path))) {
            int result = 0;
            String line = null;
            while((line = reader.readLine()) != null) {
                result *= Integer.parseInt(line);
            }
            return result;
        } catch (IOException e) {
            throw new IllegalArgumentException(path + "에 해당하는 파일이 없습니다.", e);
        }
    }
}

 

Client.java
public class Client {

    public static void main(String[] args) {
        FileProcessor fileProcessor = new FileProcessor("number.txt");
        int result = fileProcessor.process();
        System.out.println(result);
    }
}

 

1) 요구사항

number.txt 파일을 읽어서 각 row의 총합을 구하라.

 

2) 문제점

FileProcessor.java 와 MultiplyFileProcessor.java 의 비즈니스 로직을 보면 딱 한줄만 다르고, 모두 중복된다.

// FileProcessor
while((line = reader.readLine()) != null) {
    result += Integer.parseInt(line);
}

...

// MultiplyFileProcessor
while((line = reader.readLine()) != null) {
    result *= Integer.parseInt(line);
}

 

3) 추가요건

number.txt 파일을 읽어서 나눗셈을 수행해라.

DivisionFileProcessor.java 를 추가로 신규 생성한다. 이때도 단 한줄 이외의는 모두 중복코드다.

// DivisionFileProcessor
while((line = reader.readLine()) != null) {
    result /= Integer.parseInt(line);
}

 

 

적용 후 코드 (After)

FileProcessor.java
public abstract class FileProcessor {

    private String path;
    public FileProcessor(String path) {
        this.path = path;
    }

    public final int process(Operator operator) {
        try(BufferedReader reader = new BufferedReader(new FileReader(path))) {
            int result = 0;
            String line = null;
            while((line = reader.readLine()) != null) {
                /** 다른 부분 */
                result = getResult(result, Integer.parseInt(line));
            }
            return result;
        } catch (IOException e) {
            throw new IllegalArgumentException(path + "에 해당하는 파일이 없습니다.", e);
        }
    }

    protected abstract int getResult(int result, int number);

}

 

Multiply.java
public class Multiply extends FileProcessor {
    public Multiply(String path) {
        super(path);
    }

    @Override
    protected int getResult(int result, int number) {
        return result *= number;
    }

}

 

Plus
public class Plus extends FileProcessor {
    public Plus(String path) {
        super(path);
    }

    @Override
    public int getResult(int result, int number) {
        return result += number;
    }
}

 

Client
public class Client {
    public static void main(String[] args) {
        // FileProcessor fileProcessor = new Plus("number.txt");
        FileProcessor fileProcessor = new Multiply("number.txt");
        System.out.println(result);
    }
}

 

 

 

위 Before 에서 봤던 추가 요건을 다시 생각해보자.

 

1) 추가요건

number.txt 파일을 읽어서 나눗셈을 수행해라.

중복 코드는 더이상 발생하지 않는다.

getResult() 메서드를 오버라이드하여 변경되는 코드만 별도로 구성하면 완료된다.

public class Division extends FileProcessor {
    public Division(String path) {
        super(path);
    }

    @Override
    public int getResult(int result, int number) {
        return result /= number;
    }
}

 

 

 

적용 결과

 

장점
  • 템플릿 코드를 재사용하고 중복 코드를 줄일 수 있다.
  • 변경 또는 추가가 발생하면 상속을 받아서 구체적인 알고리즘만 변경할 수 있다. 

 

단점
  • 알고리즘 구조가 복잡할수록 템플릿을 유지하기 어려워진다.
  • getReulst()와 같은 추상메서드가 많아지면 코드를 읽는데에도 어려워지고, 유지보수가 힘들어진다.

 

 

 

github : https://github.com/seohaem/java/tree/master/java_GoFdesignpattern

강의 : https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4

 

 

 

반응형

Designed by JB FACTORY