본문 바로가기
개발/디자인 패턴

[Java 언어로 배우는 디자인 패턴 입문] 하위 클래스 위임 3. Template Method

by hongdor 2021. 1. 7.
728x90

출처 : 책 - java 언어로 배우는 디자인 패턴 입문

 

3. Template Method - 하위 클래스에서 구체적으로 처리하기

 

 

1. 목적

 

 - 메소드의 뼈대를 미리 만들어 두기 위해서 사용한다.

> 우리가 흔히 아는 Interface와 class 관계와 비슷한 내용이다.

 

 - 장점 : 인터페이스를 선언하고 구현 하위 클래스 인스턴스를 대입해 사용 할 수 있다.

   ( 상위 클래스형의 변수에 하위 클래스의 종류를 특정하지 않아도 프로그램이 동작할 수 있도록 한다.

     : The Liskov Substitution Principle(LSP) 원칙 )

 

 - 메소들간의 로직을 추상클래스 측에서 작성해, 공통적으로 적용할 수 있다. 

 

 

2. 예제

 

(1) 추상 클래스

public abstract class AbstractDisplay {  // 추상 클래스 AbstractDisplay
    public abstract void open();         // 하위 클래스에 구현을 맡기는 추상 메소드 (1) open
    public abstract void print();        // 하위 클래스에 구현을 맡기는 추상 메소드 (2) print
    public abstract void close();        // 하위 클래스에 구현을 맡기는 추상 메소드 (3) close
    public final void display() {        // 추상 클래스에서 구현되고 있는 메소드 display
        open();                      	 // 우선 open하고…
        for (int i = 0; i < 5; i++) {    // 5번 print을 반복하고…
            print();                    
        }
        close();     // … 마지막으로 close한다. 이것이 display 메소드에서 구현되고 있는 내용.
    }
}

 

(1) 구현 클래스1

public class CharDisplay extends AbstractDisplay {  // CharDisplay는 AbstractDisplay의 
// 하위 클래스.
    private char ch;                              // 표시해야 할 문자
    public CharDisplay(char ch) {                  // 생성자에서 전달된 문자 ch을
        this.ch = ch;                             // 필드에 기억해 둔다.
    }
    public void open() {                            // 상위 클래스에서는 추상 메소드였다.
						  // 여기에서 오버라이드해서 구현.
        System.out.print(“<<”);                     // 개시 문자열“<<”을 표시한다.
    }
    public void print() {                           // print 메소드도 여기에서 구현한다.
// 이것이 display에서 반복해서 호출된다.
        System.out.print(ch);                      // 필드에 기억해 둔 문자를 1개 표시한다.
    }
    public void close() {                           // close 메소드도 여기에서 구현.
        System.out.println(“>>”);                   // 종료 문자열 “>>”을 표시.
    }
}

 

(2) 구현 클래스2

public class StringDisplay extends AbstractDisplay {    // StringDisplay도 
// AbstrctDisplay의 하위 클래스.
    private String string;                            // 표시해야 할 문자열.
    private int width;                              // 바이트 단위로 계산한 문자열의 「폭」.
    public StringDisplay(String string) {               // 생성자에서 전달된 문자열 string을
        this.string = string;                           // 필드에 기억.
        this.width = string.getBytes().length;          // 그리고 바이트 단위의 폭도 필드에
							// 기억해 두고 나중에 사용한다.
    }
    public void open() {                             // 오버라이드해서 정의한 open 메소드.
        printLine();                                 // 이 클래스의 메소드 printLine에서
                                                     // 선을 그리고 있다.
    }
    public void print() {                               // print 메소드는
        System.out.println(“|” + string + “|”);     // 필드에 기억해 둔 문자열의
   							// 전후에 “|”을 붙여서 표시.
    }
    public void close() {                               // close 메소드는
        printLine();                                    // open 처럼 printLine 메소드에서
                                                       // 선을 그리고 있다.
    }
    private void printLine() {                  // open과 close에서 호출된 printLine 메소드이다.
 						// private이기 때문에 이 클래스 안에서만 사용된다.
        System.out.print(「+「);                // 테두리의 모서리를 표현하는”+” 마크를 표시.
        for (int i = 0; i < width; i++) {       // width개의 “-“을 표시하고
            System.out.print(「-「);            // 테두리 선으로 이용한다.
        }
        System.out.println(「+「);              // 테두리의 모서리를 표현하는 “+” 마크를 표시.
    }
}

 

(3) Main

public class Main {
    public static void main(String[] args) {
	// 'H'을 가진 CharDisplay 인스턴스를 1개 만든다>
        AbstractDisplay d1 = new CharDisplay('H');
	// “Hello, world.”을 가진 StringDisplay의 인스턴스를 1개 만든다.
        AbstractDisplay d2 = new StringDisplay(“Hello, world.”);
    	// “안녕하세요.”를 가진 StringDisplay의 인스턴스를 1개 만든다.
        AbstractDisplay d3 = new StringDisplay(“안녕하세요.”);
        d1.display();   // d1, d2, d3 모두 AbstractDisplay의 하위클래스의 인스턴스이기 때문에
        d2.display();   // 상속한 display메소드를 호출할 수 있다.
        d3.display();   // 실제 동작은 CharDisplay나 StringDisplay에서 결정한다.
    }
}
728x90

댓글