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

장선웅·2022년 7월 23일
0

템플릿 메서드 패턴이란?

  • 템플릿 메서드 패턴은 템플릿을 제공하는 메소드, 하위 클래스에게 구현을 강제하는 추상 메소드, 하위 클래스가 선택적으로 오버라이딩할 수 있는 Hook 메소드를 두는 패턴을 말한다

간단히 말하자면, 상위 클래스의 견본 메서드에서 하위 클래스가 오버라이딩한 메소드를 호출하는 패턴을 의미한다.


1. 템플릿 메서드 패턴은 왜 사용할까?

예를 들어, 차가 두 대(BMW, Audi)가 있다. 이 차들은 도로 위를 달리는 메서드(drivingRoad)를 갖고있다고 가정해보자.

//BMW 클래스
class BMW {
	//drivingRoad메서드 구현
    public void drivingRoad() {
    	System.out.println("Start the car"); // 시동걸기
        System.out.println("Manual gear"); //수동 기어로 
        System.out.println("Stop"); //정지
        System.out.println("Turn off the BMW"); //시동끄기
    }
}
//Audi 클래스
class Audi {
	//drivingRoad메서드 구현
    public void drivingRoad() {
    	System.out.println("Start the car"); // 시동걸기
        System.out.println("Auto gear"); //자동 기어로 
        System.out.println("Stop"); //정지
        System.out.println("Turn off the Audi"); //시동끄기
    }
}
//Driver 클래스(main 클래스)
public class Driver {
	public static void main(String[] args) {
    	//각각 객체 생성
        BMW bmw = new BMW();
        Audi audi = new Audi();
       	//메서드 실행
        bmw.drivingRoad();
        System.out.println("===구분선===");
        audi.drivingRoad();
    }
}
//결과값
Start the car
Manual gear
Stop
Turn off the BMW
===구분선===
Start the car
Auto gear
Stop
Turn off the Audi

더 많은 기능이 추가되면 추가될수록 중복코드는 많아지게 된다. 이를 보완하기 위한 패턴이 템플릿 메서드 패턴이다.


2. 템플릿 메서드 패턴 구현 방법

  1. 공통으로 사용하는 메서드를 포함한 차(Car) 추상 클래스 선언
abstract class Car {
    //공통 메서드 정의
    public void drivingRoad() {
        System.out.println("Start the car"); // 시동걸기
        setGear();//기어 설정
        System.out.println("Stop"); //정지
        turnOff(); // 시동 끄기
    }
    //추상 메서드 선언
    abstract void setGear();
    //turnOff메서드 정의
    void turnOff() {
        System.out.println("Turn Off");
    }
}
  1. Car추상 클래스를 상속받은 하위 클래스(BMW, Audi) 선언과 메서드 오버라이딩
//BMW 클래스
class BMW extends Car{
    //Car 클래스의 메서드 오버라이딩
    @Override
    void setGear() {
        System.out.println("Manual gear"); //수동 기어로
    }
    @Override
    void turnOff(){
        System.out.println("Turn off the BMW"); //시동 끄기(=ㅎhook메서드)
    }
}
//Audi 클래스
class Audi extends Car{
    //Car 클래스의 메서드 오버라이딩
    @Override
    void setGear() {
        System.out.println("Auto gear"); //자동 기어로
    }
    @Override
    void turnOff(){
        System.out.println("Turn off the Audi"); //시동 끄기
    }
}
//Driver 클래스(main 클래스)
public class Driver {
    public static void main(String[] args) {
        //각각 객체 생성
        BMW bmw = new BMW();
        Audi audi = new Audi();
        //메서드 실행
        bmw.drivingRoad();
        System.out.println("===구분선===");
        audi.drivingRoad();
    }
}
//결과값
Start the car
Manual gear
Stop
Turn off the BMW
===구분선===
Start the car
Auto gear
Stop
Turn off the Audi

코드만 봐서는 좀 어렵다. 하나하나 분석해보도록 하자.

템플릿 메서드 패턴 구성 요소상위(부모) 클래스 Car하위(자식) 클래스 BMW, Audi
템플릿 메서드는 공통 로직을 수행하는 부분, 공통 로직 안에서 하위 클래스에서 오버라이딩한 추상 메서드와 훅 메서드를 호출한다.drivingRoad()
템플릿 메서드에서 호출하는 추상 메서드, 하위 클래스가 반드시 오버라이딩 하도록 한다setGear()필수적으로 오버라이딩 해야한다.
템플릿 메서드에서 호출하는 훅 메서드를 하위 클래스에서 선택적으로 오버라이딩한다.turnOff()오버라이딩을 하지 않아도 "Turn Off"가 호출 된다.

3. 템플릿 메서드 패턴의 장/단점

장점

  1. 중복 코드를 줄일 수 있다.
  2. 상속을 통해 하위 클래스를 생성해 나간다(확장성에 용이하다)
  3. 하위 클래스의 역할이 줄어든다(핵심적인 로직 관리가 쉽다)
  4. 코드의 객체 지향적 구성이 가능하다

단점

  1. 추상 메서드가 늘어나기 때문에 클래스 관리가 복잡해진다.
  2. 상위 클래스를 수정해야 하는 순간, 모든 하위 클래스를 일일이 수정해야한다(수정하기 어렵다)

4. 후크(hook) 메서드란?

후크 메서드란, 위의 코드에 따르면 turnOff()메서드이다. 추상 클래스를 상속받은 하위 클래스는 abstract 키워드를 앞에 붙인 메서드를 반드시 오버라이딩해야한다. 하지만 후크 메서드는 선택적으로 오버라이딩할 수 있는 메서드이다. 이는 서브 클래스에서 확장할 수 있는 기본적인 행동을 제공하며, 안에 아무 코드가 없을 수도 있다.


5. 할리우드 원칙

  • "먼저 연락하지 마세요. 저희가 연락 드리겠습니다.(Don't call us, we will call you.)" 라는 말에서 유래되었다고 한다.
  • 할리우드 원칙을 적용하게 되면, 저수준 구성요소에 시스템에 접속을 할 수는 있지만, 언제 어떤식으로 그 구성요소들을 사용할지는 고수준 구성요소에서 결정하게 된다.
  • 즉, 저수준 구성요소에서고수준 구성요소를 집적 호출 할 수 없게 하고, 고수준 구성요소가 저수준 구성요소를 직접 호출 하는것은 허용하게 한다.

6. 의존성 부패

  • 어떤 고수준 구성요소가 저수준 구성요소에 의존하고, 그 저수준 구성요소는 다시 고수준 구성요소에 의존하는 등, 의존성이 복잡하게 꼬여있는 것을 3의존성 부패라고 한다.
  • 이는 할리우드 원칙을 적용한다면, 이를 방지할 수 있다.
profile
개발을 꿈꾸는 초짜

0개의 댓글