디자인 패턴: 템플릿 메서드 패턴

DanChu 🌟·2022년 7월 24일
0

알고리즘 구조를 메소드에 정의하고, 하위 클래스에서 알고리즘의 구조 변경없이 알고리즘을 재정의 하는 패턴. 알고리즘이 단계별로 나누어지거나, 같은 역할을 하는 메소드이지만 여러곳에서 다른 형태로 사용이 필요한 경우 유용.

즉, 변지 않을 기능은 슈퍼클래스에 만들어두고 자주 변경되거나 확장할 기능을 서브클래스가 슈퍼클래스를 상속받아서 만드는 방법


템플릿 메서드 패턴 예시

//추상 클래스 선생님
abstract class Teacher{
	
    public void start_class() {
        inside();
        attendance();
        teach();
        outside();
    }
	
    // 공통 메서드
    public void inside() {
        System.out.println("선생님이 강의실로 들어옵니다.");
    }
    
    public void attendance() {
        System.out.println("선생님이 출석을 부릅니다.");
    }
    
    public void outside() {
        System.out.println("선생님이 강의실을 나갑니다.");
    }
    
    // 추상 메서드
    abstract void teach();
}
 
// 국어 선생님
class Korean_Teacher extends Teacher{
    
    @Override
    public void teach() {
        System.out.println("선생님이 국어를 수업합니다.");
    }
}
 
//수학 선생님
class Math_Teacher extends Teacher{

    @Override
    public void teach() {
        System.out.println("선생님이 수학을 수업합니다.");
    }
}

//영어 선생님
class English_Teacher extends Teacher{

    @Override
    public void teach() {
        System.out.println("선생님이 영어를 수업합니다.");
    }
}

public class Main {
    public static void main(String[] args) {
        Korean_Teacher kr = new Korean_Teacher(); //국어
        Math_Teacher mt = new Math_Teacher(); //수학
        English_Teacher en = new English_Teacher(); //영어
        
        kr.start_class();
        System.out.println("----------------------------");
        mt.start_class();
        System.out.println("----------------------------");
        en.start_class();
    }
}

Result

모든 과목의 선생님들은 강의실에 들어오고, 출석을 부르고, 강의를 하고, 강의실을 나간다는 동일한 루틴을 가짐.
이러한 선생님의 기본 루틴을 추상클래스(선생님)에 정의하고 공통 알고리즘을 구성.
이후 각각 과목에 대한 하위 클래스를 생성하여 기본 루틴인 선생님의 루틴을 상속받고, 여기에 각 과목별 추가/확장 기능을 정의하는 것으로 템플릿 메소드 패턴 적용.


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

장점

  • 중복 코드를 줄일 수 있음
  • 자식 클래스 역할을 줄여 핵심 로직 관리가 용이해짐
  • 코드를 객체지향적으로 구성하기 쉬워짐

단점

  • 추상 메소드가 많아지면서 클래스 관리가 복잡해짐
  • 클래스간 관계와 코드가 꼬일 수 있음

후크(hook)란?

추상 클래스에 들어있는, 아무 일도 하지 않거나 기본 행동을 정의하는 메소드로, 서브 클래스에서 hook()을 오버라이드 하여 다양한 위치에서 알고리즘에 끼어들 수 있음.

할리우드 원칙과 의존성 부패

할리우드 원칙

템플릿 메서드는 "할리우드 원칙(Hollywood principle)"이라는 역전된 제어 구조를 끌어냅니다. "전화하지 마세요. 우리가 연락할게요(Don't call us, we'll call you)."라는 것입니다. 다시 말해, 부모 클래스는 서브클래스에 정의된 연산을 호출할 수 있지만 반대 방향의 호출은 안 됩니다.

의존성 부패

헐리우드 원칙을 활용하면 "의존성 부패(dependency rot)"를 방지할 수 있습니다. 어떤 고수준 구성요소가 저수준 구성요소에 의존하고, 그 저수준 구성요소는 다시 고수준 구성요소에 의존하고, 그 고수준 구성요소는 다시 또 다른 구성요소에 의존하고, 그 다른 구성요소는 또 저수준 구성요소에 의존하는 것과 같은 식으로 의존성이 복잡하게 꼬여있는 것을 의존성 부패라고 부릅니다. 이렇게 의존성이 부패되면 시스템이 어떤 식으로 디자인된 것인지 거의 아무도 알아볼 수 없게 되죠.

헐리우드 원칙을 사용하면, 저수준 구성요소에서 시스템에 접속을 할 수는 있지만, 언제 어떤 식으로 그 구성요소들을 사용할지는 고수준 구성요소에서 결정하게 됩니다. 즉, 고수준 구성요소에서 저수준 구성요소에게 "먼저 연락하지 마세요. 제가 먼저 연락 드리겠습니다"라고 얘기를 하는 것과 같죠.

할리우드 원칙 vs. 의존성 부패

의존성 뒤집기 원칙

가능한 구상 클래스 사용을 줄이고 대신 추상화된 것을 사용해야 함

할리우드 원칙

저수준 구성요소가 컴퓨테이션에 참여할 수 있으면서도 저수준과 고수준 계층 사이에 의존성을 만들지 않도록 프레임워크 또는 구성요소를 구축하기 위한 기법

따라서 객체를 분리시킨다는 목표를 공유하고 있으나,의존성 뒤집기 원칙이 훨씬 더 강하고 일반적인 내용을 담고 있다고 할 수 있다.

참고

저수준 구성요소는 고수준 구성요소에 있는 메소드를 호출하지 못하는 것은 아님. 상속을 통해 호출하는 경우가 종종 있지만 저수준과 고수준 구성요소 사이에확연하게 드러나는 순환 의존성만은 피해야 함.





references

0개의 댓글