자바로 구현하는 템플릿 메소드 패턴: 재사용 가능한 알고리즘

자바로 구현하는 템플릿 메소드 패턴

템플릿 메소드 패턴은 객체 지향 프로그래밍에서 매우 중요한 개념 중 하나이다. 이 패턴은 알고리즘의 뼈대를 만들어 놓고, 하위 클래스에서 구체적인 알고리즘을 구현하도록 하는 디자인 패턴이다. 이는 코드의 재사용성을 높이고, 개발 시간을 단축시킬 수 있다. 이 글에서는 자바로 구현하는 템플릿 메소드 패턴에 대해 자세히 다루어보고자 한다.

재사용 가능한 알고리즘의 핵심

템플릿 메소드 패턴의 핵심은 재사용 가능한 알고리즘이다. 이 패턴을 사용하면 공통적인 알고리즘을 하나의 메소드로 만들어 놓고, 하위 클래스에서는 이 메소드를 상속받아 구체적인 구현을 추가할 수 있다. 이로써 코드의 재사용성을 높일 수 있다.

예를 들어, 여러 종류의 차량을 만든다고 가정해보자. 각 차량은 엔진을 가지고 있으며, 차량을 운전할 때는 연료를 사용한다. 이 경우, 모든 차량에 공통적으로 적용되는 메소드인 "연료 공급" 메소드가 있다. 이 메소드는 연료를 공급하고, 연료가 부족할 경우 경고음을 울리는 등의 기능을 수행한다. 이러한 공통적인 기능을 템플릿 메소드 패턴으로 구현하면, 차량마다 연료 공급 메소드를 구현하지 않아도 된다.

추상 클래스와 구현 클래스 설계

템플릿 메소드 패턴을 구현하기 위해서는 먼저 추상 클래스와 구현 클래스를 설계해야 한다. 추상 클래스는 공통적인 알고리즘을 포함하고 있으며, 하위 클래스에서는 이 추상 클래스를 상속받아 구체적인 구현을 추가한다. 구현 클래스는 추상 클래스를 상속받아 구현된 클래스로, 구체적인 알고리즘을 구현한다.

예를 들어, 차량을 만든다고 가정해보자. 이 경우, 추상 클래스는 "차량" 클래스가 되며, 이 클래스에는 "엔진"과 "연료 공급" 메소드가 포함된다. 구현 클래스는 "승용차"와 "트럭" 클래스가 될 수 있으며, 각각은 "차량" 클래스를 상속받아 "엔진"과 "연료 공급" 메소드를 구현한다.

템플릿 메소드 패턴의 장단점과 예제 코드

템플릿 메소드 패턴은 코드의 재사용성을 높이고, 개발 시간을 단축시키는 장점이 있다. 하지만, 추상 클래스와 구현 클래스를 설계하는 데 많은 시간이 소요될 수 있으며, 일부 개발자들은 이를 복잡하게 느낄 수 있다.

다음은 자바로 구현하는 템플릿 메소드 패턴의 예제 코드이다.

public abstract class Car {
    protected Engine engine;

    public Car(Engine engine) {
        this.engine = engine;
    }

    public void start() {
        engine.start();
        System.out.println("Car started");
    }

    public void stop() {
        engine.stop();
        System.out.println("Car stopped");
    }

    public abstract void fillFuel();
}

public class Sedan extends Car {
    public Sedan(Engine engine) {
        super(engine);
    }

    @Override
    public void fillFuel() {
        System.out.println("Fuel filled for Sedan");
    }
}

public class SUV extends Car {
    public SUV(Engine engine) {
        super(engine);
    }

    @Override
    public void fillFuel() {
        System.out.println("Fuel filled for SUV");
    }
}

public interface Engine {
    public void start();
    public void stop();
}

public class DieselEngine implements Engine {
    @Override
    public void start() {
        System.out.println("Diesel engine started");
    }

    @Override
    public void stop() {
        System.out.println("Diesel engine stopped");
    }
}

public class GasolineEngine implements Engine {
    @Override
    public void start() {
        System.out.println("Gasoline engine started");
    }

    @Override
    public void stop() {
        System.out.println("Gasoline engine stopped");
    }
}

public class TemplateMethodPatternDemo {
    public static void main(String[] args) {
        Engine dieselEngine = new DieselEngine();
        Car sedan = new Sedan(dieselEngine);
        sedan.start();
        sedan.fillFuel();
        sedan.stop();

        Engine gasolineEngine = new GasolineEngine();
        Car suv = new SUV(gasolineEngine);
        suv.start();
        suv.fillFuel();
        suv.stop();
    }
}

위 코드에서, "Car" 추상 클래스는 "Engine"을 가지고 있으며, "start"와 "stop" 메소드를 구현하고 있다. "fillFuel" 메소드는 추상 메소드로, 하위 클래스에서 구현된다. "Sedan"과 "SUV" 클래스는 "Car" 추상 클래스를 상속받아 "fillFuel" 메소드를 구현한다. "Engine" 인터페이스는 "start"와 "stop" 메소드를 가지고 있으며, "DieselEngine"과 "GasolineEngine" 클래스는 이 인터페이스를 구현한다.

위 코드에서는 "TemplateMethodPatternDemo" 클래스에서 "Sedan"과 "SUV" 객체를 생성하고, 각 객체의 "start", "fillFuel", "stop" 메소드를 호출한다. 이 때, "start"와 "stop" 메소드는 "Car" 추상 클래스에서 구현되어 있으며, "fillFuel" 메소드는 하위 클래스에서 구현된다.

결론

이 글에서는 자바로 구현하는 템플릿 메소드 패턴에 대해 다뤘다. 템플릿 메소드 패턴은 코드의 재사용성을 높이고, 개발 시간을 단축시키는 장점이 있으며, 추상 클래스와 구현 클래스를 설계하는 데 많은 시간이 소요될 수 있다는 단점이 있다. 하지만, 객체 지향 프로그래밍에서는 이러한 패턴을 효과적으로 사용하여 코드의 유지 보수성과 확장성을 높이는 것이 중요하다.