본문 바로가기

우테코/level1(코틀린)

[우테코] 템플릿 메서드 패턴 간단요약

너무 바쁘고 정신머리 없어서 글을 쓸수가 없다. 

 

일단 작은것부터 쓰고 모으는 형태로 해야겠다 글쓰기를 마이크로 서비스화 시켜보자

 

요즘 패턴들 배워보는게 너무 재미있는거같다.

그 중 최고로 공감했던 템플릿 메서드 패턴에대해서 프롤로그에 남긴김에 블로그에도 옮겨적는다.

 

블랙잭 하면서 배운거니 나중에 블랙잭에서도 계속 등장 할 것이다.

 

아니 자꾸 글쓰면서도 자꾸 띄어쓰기 불편하면 Command + Option + L 를 누르고 있다. 돌아버린것같다.

 

이제 한번 템플릿 메서드 패턴을 살펴보자

템플릿 메서드 패턴

자 항상 하던 고민을 긁어주는 우리의 패턴맨 제이슨이 무심하게 던져놓고간 템플릿 메서드 패턴이다.

->이런 고민해본적 있지않는가?

아니 다 똑같은데 이부분만 다른거 어떻게 재활용못하나?

이 의문에 대한 나의 얼기설기 대책은 여러군데에서 사용되는 함수를 오브젝트로 빼놓고 분기해야하는 부분을 고차함수로 넘겨서 원하는 부분을 조작해주곤 했다.

object 어쩌구오브젝트 {
    fun 공통로직분리함수(개별로직: () -> Any) {
        공통로직....
        개별로직()
    }
}

고차함수로 받아서 시기적절할때 사용해주는 방법을 이용했다.

어떻게 얼기설기 해결했지만 문제점은 object로 로직이 넘어가있기 때문에 각각의 인스턴스에 포함되어있는 상태값들은 사용할수가 없어 반쪽짜리 해결책이였다.

이런 답답함을 안고 몇년을 헤맷는지 모르겠다.

이떄 나타난 빛과같은 패턴 템플릿 메서드 패턴 -> 처음 듣자마자 막힌코가 뚫리는 느낌이였다.

이제 템플릿 메서드 패턴이 뭔지 살펴보자

일단 예시 상황을 살펴보자

블랙잭 미션 구현중 카드를 뽑을수있는 상태들을 구현하던 와중 FirstTurn(카드가 한장인 상태)와 Hit(두장 이상인데 카드 계속 뽑을수있는 상태) 에서 동시에 draw라는 카드를 뽑는 함수를 구현해야했다 분명 비슷한 로직이기에 내부 조건문 빼고는 같은 코드를 공유하는 상황이였다.

이런상황에서 나의 기존 얼기설기 해결책으로는 상태값에 접근할수 없어 활용할수없었다.

이럴때 상위에 ProgressAble(대충 카드 뽑을수있는 상태라는 뜻) 이런 추상클래스를 통해서 템플릿을 미리 만들어주고

abstract class ProgressAble(override val hand: CardBunch) : State {
    override fun draw(card: Card): State {
        val addedHand = CardBunch(hand.cards + card)
        return returnCondition(addedHand)
    }
​
    abstract fun returnCondition(hand: CardBunch): State
}

draw함수로 공통적이게 쓰이는 틀을 미리 작성해준다.

다음 내부의 각각 다르게 사용되는 로직이 들어갈 자리에 함수를 abstract로 만들어준다(returnCondition).

이럴경우 이 추상클래스를 각각의 사용처 클래스에서 상속을받고 abstract함수를 적절히 다르게 오버라이딩 해주면 원하는 기능 뚝딱 중복을 피하면서 분기처리가 가능했다.

-> 이게 개쩌는게 뭐냐 상속이니까 상태값을 넘겨서 기존 인스턴스의 상태값을 넘겨받아 사용할수있다 -> 보면 기존 분리하려던 Class가 가지고있는 hand 상태값을 추상클래스도 받는다.

사용처1 FirstTurn

class FirstTurn(override val hand: CardBunch) : ProgressAble(hand) {
​
    override fun returnCondition(hand: CardBunch): State {
        if (hand.getTotalScore() == 21 && hand.cards.size == 2) return BlackJack(hand)
        return Hit(hand)
    }
}

사용처2 Hit

class Hit(override val hand: CardBunch) : ProgressAble(hand) {
​
    override fun returnCondition(hand: CardBunch): State {
        if (hand.isBurst()) return Burst(hand)
        return (Hit(hand))
    }
​
    override fun stay(): State = Stay(hand)
}

즉 사용해보면 확 와닿겠지만 인라인 마냥 추상클래스에 있는 코드를 원하는 부분만 오버라이딩하면 마치 그 코드 자체를 가지고있는 것처럼 자연스럽게 사용할 수 있다.

이름도 잘지었다 템플릿 메서드 패턴 안드로이드 하면 라이브 템플릿 해놓고 원하는것만 딱딱 넣어서 간편하게 사용했을것이다.

이 패턴또한 재활용시킬수 있게 원하는 부분만 함수를 딱딱 넣어줘서 템플릿처럼 활용할수 있는 것이다.

정말 피부에 와닿는 패턴이였고 많이 이용하게 될것같다.

 

이제 후속작은 아마 상태패턴과 어댑터 패턴이 될것같다. 얼른 시간내서 글을 써봐야겠다.