ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [헤드 퍼스트 디자인 패턴] 8장. 템플릿 메소드 패턴
    Book/헤드 퍼스트 디자인 패턴 2023. 6. 19. 11:54

    8장. 템플릿 메소드 패턴: 알고리즘 캡슐화하기

    커피와 차를 만드는 단계에는 중복된 부분이 많다. 두 클래스를 만든다고 할 때, 어떻게 하면 중복된 코드를 없앨 수 있을까?

    이럴 때 우리는 템플릿 메소드 패턴을 사용할 수 있다.

     

    템플릿 메소드 패턴의 정의

    템플릿 페소드 패턴은 알고리즘의 골격을 정의한다. 템플릿 메소드를 사용하면 알고리즘의 일부 단계를 서브클래스에서 구현할 수 있으며, 알고리즘의 구조는 그대로 유지하며서 알고리즘의 특정 단계를 서브클래스에서 재정의할 수도 있다.

     

    간단하게 말하자면 템플릿 메소드 패턴은 알고리즘의 템플릿을 만든다. 템플릿이란, 일련의 단계로 알고리즘을 정의한 메소드이다. 여러 단계 가운데 하나 이상의 단계가 추상 메소드로 정의되며 그 추상 메소드는 서브클래스에서 구현된다. 이러면 서브 클래스가 일부분의 구현을 처리하게 하면서도 알고리즘의 구조는 바꾸지 않아도 된다. 

     

    클래스 다이어그램을 살펴보면 다음과 같다.

     

    템플릿 메소드 속 후크

    후크는 추상 클래스에서 선언되지만 기본적인 내용만 구성 구현되어 있거나 아무 코드도 들어있지 않은 메소드이다. 이러면 서브 클래스는 다양한 위치에서 알고리즘에 끼어들 수 있다. 후크가 있으면 그 메소드를 오버라이드 할 수 도 있고 그냥 넘어갈 수도 있다. 오버라이드하지 않으면 추상 클래스에서 기본으로 제공한 코드가 실행된다.

    할리우드 원칙

    할리우드 원칙을 활용하면 의존성 부패를 방지할 수 있다. 어떤 고수준 구성 요소가 저수준 구성 요소에 의존하고, 그 저수준 구성요소는 다시 고수준 구성 요소에 의존하고.... 이런 식으로 의존성이 복잡하게 꼬여있는 상황을 의존성이 부패했다고 부른다. 이렇게 의존성이 부패하면 시스템 디자인이 어떤 식으로 되어 있는지 아무도 알아볼 수 없다. 

     

    할리우드 원칙을 사용하면 저수준 구성 요소가 시스템에 접속할 수는 있지만 어떻게 그 구성 요소를 사용할지는 고수준 구성 요소가 결정한다. 즉, 고수준 구성 요소가 저수준 구성 요소에게 "먼저 연락하지 마세요, 제가 먼저 연락드리겠습니다."라고 말하는 것과 동일하다.

     

    자바 API 속 템플릿 메소드 패턴 알아보기

    자바의 Arrays에는 정렬할 때 쓸 수 있는 편리한 템플릿 메소드가 포함되어 있다.

    public static void sort(Object a) {
    	Object aux[] = (Object[])a.clone();
    	mergeSort(aux, a, 0, a.length, 0);
    	//mergesort() 메소드에는 정렬 알고리즘이 들어있으며 compareTo()메서드에 의해 결과가 결정됩니다. 정렬이 실제로 어떤 식으로 자바 소스 코드를 확인해 보세요.
    } 
       
       
    private static void mergeSort(Object src[], Object dest[], int low, int high, int off){
    {
    	//많은 코드
    		for (int i = low; i<high; i++){
    			for (int j=i; j>low && 
                	((Comparable)dest[j-1]).compareTo((Comparable)dest[j])>0;j--)
    			{
    				swap(dest, j, j-1);
    			}
    		}
    		//많은 코드
    }

    compareTo()란?

    compareTo() 메소드는 두 객체를 비교해서 그 대소 관계를 리턴하는 메소드이다. sort 메소드에서 그 결과를 사용해서 배열을 정렬한다. 따라서 정렬을 시행하려면 compareTo() 메소드를 구현해야한다. 이 메소드를 구현하면 배열 클래스에 들어있는 알고리즘이 완성되고, 오리 배열을 정렬할 수 있다.

    정렬 단계

    1. Arrays 클래스에 있는 sort() 템플릿 메소드를 호출한다. 
    2. sort 메소드와 그 보조 메소드인 mergeSort()에서 정렬 작업을 처리한다.
    3. 배열을 정렬하려면 전체 목록이 정렬될 때 까지 두 항목을 하나씩 비교해야한다. sort()메소드는 두 객체를 비교할 때 compareTo()메소드에 의존한다. 한 객체의 compareTo() 메소드를 호출할 때 비교해야 할 다른 객체를 매개 변수로 전달한다.
    4. 비교한 결과 순서가 맞지 않으면 Arrays에 들어있는 swap() 구상 메소드를 사용하여 두 오리 객체를 맞바꾼다.
    5. 이 과정을 계속해서 반복한다.

    전략 패턴과의 차이점

    전략 패턴은 알고리즘을 구현할 때 상속을 사용하지 않는다. 클라이언트에게 객체 구성으로 알고리즘을 구현할 지말지 선택할 기회를 준다. 

    템플릿 메소드 패턴에서는 코드 중복이 거의 발생하지 않고 중복되는 코드는 모두 슈퍼 클래스에 들어있어 서브클래스도 공유받을 수있다.

Designed by Tistory.