지난 게시글에서 퍼사드 패턴을 출근 준비로 표현했던 것 처럼..!
이번 템플릿 메소드 패턴도 동일하게 정리를 해봐야겠다.!
출근 준비에 대한 것을 큰 카테고리? 로 보면
알람 -> 씻기 -> 옷입기 -> 이동수단 으로 볼 수 있다.
A와 B의 준비 단계를 보자!
A : 알람 -> 씻기 -> 옷입기 (원피스) -> 이동수단 (자동차)
B : 알람 -> 씻기 -> 옷입기 (파란티) -> 이동수단 (버스)
이다.!
여기서 A,B가 다르지 않고 동일한 과정은 빨간색으로, 다른 과정은 파란색으로 표시를 해보았다.
이를 코드로 표현을 해보자.!
"A" 의 준비 과정
class ReadyToWorkA {
public void start(TextView tv) {
alarm(tv);
wash(tv);
clothes(tv);
vehicle(tv);
}
public void alarm(TextView tv) {
tv.setText( (String) tv.getText() + "\nalarm!!" );
}
public void wash(TextView tv) {
tv.setText( (String) tv.getText() + "\nwash!!" );
}
public void clothes(TextView tv) {
tv.setText( (String) tv.getText() + "\nclothes - red!!" );
}
public void vehicle(TextView tv) {
tv.setText( (String) tv.getText() + "\nvehicle - car!!" );
}
}
"B" 의 준비과정
class ReadyToWorkB {
public void start(TextView tv) {
alarm(tv);
wash(tv);
clothes(tv);
vehicle(tv);
}
public void alarm(TextView tv) {
tv.setText( (String) tv.getText() + "\nalarm!!" );
}
public void wash(TextView tv) {
tv.setText( (String) tv.getText() + "\nwash!!" );
}
public void clothes(TextView tv) {
tv.setText( (String) tv.getText() + "\nclothes - blue!!" );
}
public void vehicle(TextView tv) {
tv.setText( (String) tv.getText() + "\nvehicle - bus!!" );
}
}
만약의 "C"의 준비 과정이 추가된다면 어떻게 해야할까?
class ReadyToWorkC {
public void start(TextView tv) {
alarm(tv);
wash(tv);
clothes(tv);
vehicle(tv);
}
public void alarm(TextView tv) {
tv.setText( (String) tv.getText() + "\nalarm!!" );
}
public void wash(TextView tv) {
tv.setText( (String) tv.getText() + "\nwash!!" );
}
public void clothes(TextView tv) {
tv.setText( (String) tv.getText() + "\nclothes - hawaiian!!" );
}
public void vehicle(TextView tv) {
tv.setText( (String) tv.getText() + "\nvehicle - train!!" );
}
}
그런데.. D,E.....Z까지의 유형이 추가된다면
하나하나 추가해 주기엔 중복된 메소드 (start, alarm, wash) 의 경우에는 계속 동일한 메소드를 추가하는 것은 불필요한 작업처럼 느껴진다.
이럴떄 사용 할 수 있는 디자인패턴이 템플릿 메소드 패턴 이다.
템플릿 메소드 패턴이란?
메소드에서 알고리즘의 골격을 정의해서 알고리즘의 구조는 유지하면서 특정 단계를 재정의 할 수 있게 하는 패턴.
알고리즘의 각 단계를 정의하고, 그 중 한 개 이상의 단계가 서브 클래스에 의해 제공 될 수 있는 패턴.
위의 예시로 다시 쉽게 설명하자면,
알람 -> 씻기 -> 옷입기 -> 이동수단 에서
각 단계의 순서를 나타내는 start 함수를 포함한 중복되는 단계를 골격으로 정의하고,
중복되지 않은 단계 는 서브 클래스에 의해 재정의 될 수 있게 하는 것이다.
일단 내가 만든 예제에서 중복되는 부분은 아래와 같다.
public void start(TextView tv) {
alarm(tv);
wash(tv);
clothes(tv);
vehicle(tv);
}
public void alarm(TextView tv) {
tv.setText( (String) tv.getText() + "\nalarm!!" );
}
public void wash(TextView tv) {
tv.setText( (String) tv.getText() + "\nwash!!" );
}
중복되지 않은 부분이다.
"A"
public void clothes(TextView tv) {
tv.setText( (String) tv.getText() + "\nclothes - red!!" );
}
public void vehicle(TextView tv) {
tv.setText( (String) tv.getText() + "\nvehicle - car!!" );
}
"B"
public void clothes(TextView tv) {
tv.setText( (String) tv.getText() + "\nclothes - blue!!" );
}
public void vehicle(TextView tv) {
tv.setText( (String) tv.getText() + "\nvehicle - bus!!" );
}
"C"
public void clothes(TextView tv) {
tv.setText( (String) tv.getText() + "\nclothes - hawaiian!!" );
}
public void vehicle(TextView tv) {
tv.setText( (String) tv.getText() + "\nvehicle - train!!" );
}
위 과정을 템플릿 메소드로 표현하기 위해서는 final 과 abstract 두 가지 용어의 뜻을 알아야한다.
내가 정의한 두 용어의 뜻은..!
- final : 오버라이드를 못하도록 정의하는 것.
- abstract : "추상" 으로 재 정의가 꼭 필요한 것.
이제 위 과정을
ReadyToWork abstract class로 구현을 해보자!
먼저 각 단계의 순서를 알려주면서 class의 골격 역할을 해주는 부분이다.
위 예제에서 준비하는 순서는 A,B...Z까지 동일하기 때문에
순서는 재정의가 되면 절대 안되는 부분으로 final 로 표현을 해야한다.!
public final void start(TextView tv) {
alarm(tv);
wash(tv);
clothes(tv);
vehicle(tv);
}
alarm 과 wash의 경우 A,B,C가 동일해 A~C까지는 재정의 할 필요는 없지만,
달라질 경우 재정의가 가능하도록 할 수 있도록 구현해준다.
public void alarm(TextView tv) {
tv.setText( (String) tv.getText() + "\nalarm!!" );
}
public void wash(TextView tv) {
tv.setText( (String) tv.getText() + "\nwash!!" );
}
clothes와 vehicle 의 경우 다른 경우가 대부분이기 때문에, 무조건 재정의 하도록 구현해준다.
abstract void clothes(TextView tv);
abstract void vehicle(TextView tv);
여기서 !!
위처럼 아무 내용도 없는 코드를 후크 라고 한다.
후크란?
추상클래스에서 선언되는 메소드
기본적인 내용만 있거나 아무 코드도 없는 메소드
서브클래스에서 필요에 따라 재정의해 사용하는 메소드
로 정의할 수 있다.
자바의 스윗프레임을 예로 들 수 있다.
전체적인 소스를 보면, 아래와 같이 표현 할 수 있다.
abstract class ReadyToWork {
public final void start(TextView tv) {
alarm(tv);
wash(tv);
clothes(tv);
vehicle(tv);
}
public void alarm(TextView tv) {
tv.setText( (String) tv.getText() + "\nalarm!!" );
}
public void wash(TextView tv) {
tv.setText( (String) tv.getText() + "\nwash!!" );
}
abstract void clothes(TextView tv);
abstract void vehicle(TextView tv);
}
위에 템플릿을 상속받아 D의 경우를 만들어 보았다.
D 의 경우 준비 순서는
no alarm -> 씻기 -> 옷 입기 (오렌지 옷) -> 이동 수단 (택시) 이다.
class ReadyToWorkD extends ReadyToWork {
@Override
public void alarm(TextView tv) {
tv.setText( (String) tv.getText() + "\nno alarm !!");
}
@Override
void clothes(TextView tv) {
tv.setText( (String) tv.getText() + "\nclothes - orange !!");
}
@Override
void vehicle(TextView tv) {
tv.setText( (String) tv.getText() + "\nvehicle - taxi !!");
}
}
이 D의 순서를 보기 위해서는
ReadyToWorkD readyToWorkD = new ReadyToWorkD();
readyToWorkD.start(textView);
로 해주면 된다.
동작 화면은 아래와 같다.
- 초기 상태
- 버튼을 누르면 D 의 준비 과정이 보인다.!
전체적인 소스는 아래와 같다.!
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class TemplateMethodActivity extends Activity implements View.OnClickListener {
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_template_method);
init();
}
private void init(){
findViewById(R.id.buttonToReady).setOnClickListener(this);
textView = findViewById(R.id.textView);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.buttonToReady:
ReadyToWorkD readyToWorkD = new ReadyToWorkD();
readyToWorkD.start(textView);
break;
}
}
}
class ReadyToWorkA {
public void start(TextView tv) {
alarm(tv);
wash(tv);
clothes(tv);
vehicle(tv);
}
public void alarm(TextView tv) {
tv.setText( (String) tv.getText() + "\nalarm!!" );
}
public void wash(TextView tv) {
tv.setText( (String) tv.getText() + "\nwash!!" );
}
public void clothes(TextView tv) {
tv.setText( (String) tv.getText() + "\nclothes - red!!" );
}
public void vehicle(TextView tv) {
tv.setText( (String) tv.getText() + "\nvehicle - car!!" );
}
}
class ReadyToWorkB {
public void start(TextView tv) {
alarm(tv);
wash(tv);
clothes(tv);
vehicle(tv);
}
public void alarm(TextView tv) {
tv.setText( (String) tv.getText() + "\nalarm!!" );
}
public void wash(TextView tv) {
tv.setText( (String) tv.getText() + "\nwash!!" );
}
public void clothes(TextView tv) {
tv.setText( (String) tv.getText() + "\nclothes - blue!!" );
}
public void vehicle(TextView tv) {
tv.setText( (String) tv.getText() + "\nvehicle - bus!!" );
}
}
class ReadyToWorkC {
public void start(TextView tv) {
alarm(tv);
wash(tv);
clothes(tv);
vehicle(tv);
}
public void alarm(TextView tv) {
tv.setText( (String) tv.getText() + "\nalarm!!" );
}
public void wash(TextView tv) {
tv.setText( (String) tv.getText() + "\nwash!!" );
}
public void clothes(TextView tv) {
tv.setText( (String) tv.getText() + "\nclothes - hawaiian!!" );
}
public void vehicle(TextView tv) {
tv.setText( (String) tv.getText() + "\nvehicle - train!!" );
}
}
abstract class ReadyToWork {
public final void start(TextView tv) {
alarm(tv);
wash(tv);
clothes(tv);
vehicle(tv);
}
public void alarm(TextView tv) {
tv.setText( (String) tv.getText() + "\nalarm!!" );
}
public void wash(TextView tv) {
tv.setText( (String) tv.getText() + "\nwash!!" );
}
abstract void clothes(TextView tv);
abstract void vehicle(TextView tv);
}
class ReadyToWorkD extends ReadyToWork {
@Override
public void alarm(TextView tv) {
tv.setText( (String) tv.getText() + "\nno alarm !!");
}
@Override
void clothes(TextView tv) {
tv.setText( (String) tv.getText() + "\nclothes - orange !!");
}
@Override
void vehicle(TextView tv) {
tv.setText( (String) tv.getText() + "\nvehicle - taxi !!");
}
}
끄읐!
'SELF STUDY > Design Pattern' 카테고리의 다른 글
[디자인패턴] 퍼사드 패턴 | Facade Pattern | 안드로이드 예제 (0) | 2021.12.27 |
---|---|
[Design Pattern] 어댑터 패턴 | Adapter Pattern (0) | 2021.12.20 |
[디자인패턴] 커맨드 패턴 | Command Pattern | 안드로이드 예제 (0) | 2021.09.29 |
[디자인패턴] 데코레이터 패턴 | Decorator pattern (0) | 2021.09.01 |
[디자인 패턴] Observer pattern | 옵저버 패턴 (0) | 2021.08.18 |