본문 바로가기
컴퓨터 과학/디자인패턴

[디자인패턴] 행위 패턴(11) : 템플릿 메소드(Template Method)

by webcodur 2024. 3. 25.
728x90

목차

     

    템플릿 메소드(Template Method)

    템플릿 메소드 패턴은 디자인 패턴의 일종으로, 알고리즘의 구조를 메소드에 정의하고, 알고리즘의 일부 단계를 서브클래스에서 구현할 수 있도록 하여 전체 알고리즘의 구조를 변경하지 않고도 특정 단계를 재정의할 수 있도록 한다. 이 패턴의 이름은 "템플릿"이라는 단어에서 유래했다. 템플릿은 일종의 틀을 의미하는데, 템플릿 메소드 패턴에서는 알고리즘의 틀(구조)을 정의하고, 그 틀 안에서 일부 내용을 변경할 수 있도록 한다는 개념에서 비롯되었다. 단순히 추상 클래스라는 문법적인 틀의 목적과 가장 유사하다고 볼 수 있는 개념이다.

     

    패턴 미적용 예시

    먼저, 템플릿 메소드 패턴을 적용하지 않은 상황에서의 코드를 살펴보자. 이 예시에서는 간단한 게임 프로그램을 만드는 경우를 가정한다. 각 게임은 시작하기 전 준비 과정, 게임 실행, 게임 종료 후 처리 과정을 갖는다고 가정한다. 하지만 템플릿 메소드 패턴을 적용하지 않았을 때, 각 게임마다 중복된 코드를 작성해야 하는 문제가 발생할 수 있다.

    using System;
    
    class AdventureGame
    {
        public void Play()
        {
            // 준비 과정
            Console.WriteLine("모험 게임 준비...");
            // 게임 실행
            Console.WriteLine("모험 게임 실행 중...");
            // 게임 종료 후 처리
            Console.WriteLine("모험 게임 종료.");
        }
    }
    
    class RacingGame
    {
        public void Play()
        {
            // 준비 과정
            Console.WriteLine("레이싱 게임 준비...");
            // 게임 실행
            Console.WriteLine("레이싱 게임 실행 중...");
            // 게임 종료 후 처리
            Console.WriteLine("레이싱 게임 종료.");
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            AdventureGame adventureGame = new AdventureGame();
            adventureGame.Play();
    
            RacingGame racingGame = new RacingGame();
            racingGame.Play();
        }
    }
    

     

    위 코드에서 볼 수 있듯이, AdventureGame 클래스와 RacingGame 클래스 모두 게임을 준비, 실행, 종료하는 과정이 유사하다. 이렇게 중복된 코드는 유지보수를 어렵게 만들고, 확장성을 저해한다.

     

    패턴 적용 예시

    템플릿 메소드 패턴을 적용해 볼 때, 기본적인 구조를 가지는 추상 클래스를 정의하고, 이를 상속받아 각 게임 특성에 맞게 구현하는 방식으로 가보자. 이렇게 하면, 게임의 준비, 실행, 종료 과정이 각각의 게임마다 동일하게 적용되어야 하는 구조를 가지면서도, 각 단계에서의 구체적인 행위는 서브클래스에서 정의할 수 있게 된다. 이는 중복 코드를 줄이고, 유지보수성을 향상시킬 수 있다. 이 때 공통 구조를 인터페이스가 아닌 추상 클래스로 세워두는 이유는 공통 구현도 필요하면 사용할 수 있게끔 하기 위함이다.

    using System;
    
    // 게임의 기본 틀을 정의하는 추상 클래스
    abstract class Game
    {
        // 템플릿 메소드 정의
        public void Play()
        {
            Prepare();
            PlayGame();
            EndGame();
        }
    
        // 준비 단계, 서브클래스에서 구체적 구현 필요
        protected abstract void Prepare();
    
        // 게임 실행 단계, 서브클래스에서 구체적 구현 필요
        protected abstract void PlayGame();
    
        // 게임 종료 단계, 서브클래스에서 구체적 구현 필요
        protected abstract void EndGame();
    }
    
    // 모험 게임 구현
    class AdventureGame : Game
    {
        protected override void Prepare()
        {
            Console.WriteLine("모험 게임 준비...");
        }
    
        protected override void PlayGame()
        {
            Console.WriteLine("모험 게임 실행 중...");
        }
    
        protected override void EndGame()
        {
            Console.WriteLine("모험 게임 종료.");
        }
    }
    
    // 레이싱 게임 구현
    class RacingGame : Game
    {
        protected override void Prepare()
        {
            Console.WriteLine("레이싱 게임 준비...");
        }
    
        protected override void PlayGame()
        {
            Console.WriteLine("레이싱 게임 실행 중...");
        }
    
        protected override void EndGame()
        {
            Console.WriteLine("레이싱 게임 종료.");
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Game adventureGame = new AdventureGame();
            adventureGame.Play();
    
            Game racingGame = new RacingGame();
            racingGame.Play();
        }
    }
    

     

    템플릿 메소드 패턴을 적용하면, Game 클래스는 게임이 가지는 공통적인 구조(템플릿)를 정의하고, 이를 상속받는 AdventureGame RacingGame 클래스는 각 게임의 특성에 맞는 구체적인 행동을 구현한다. 이 방식은 중복 코드를 줄이고 각 게임의 구현을 더욱 명확하게 분리할 수 있게 해주며, 새로운 게임을 추가하거나 기존 게임을 수정할 때의 유연성과 확장성을 크게 향상시킨다.