๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
develop_kr/์ด๋ก 

๐ŸŽฏ ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ ํŒจํ„ด: ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๊ณจ๊ฒฉ์„ ์ •์˜ํ•˜๋Š” ๋””์ž์ธ ํŒจํ„ด

by JSsunday 2025. 7. 5.
728x90
๋ฐ˜์‘ํ˜•

๐Ÿ“š ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ ํŒจํ„ด์ด๋ž€?

ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ ํŒจํ„ด(Template Method Pattern)์€ ํ–‰๋™ ํŒจํ„ด(Behavioral Pattern) ์ค‘ ํ•˜๋‚˜๋กœ, ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๊ณจ๊ฒฉ์„ ์ƒ์œ„ ํด๋ž˜์Šค์—์„œ ์ •์˜ํ•˜๊ณ  ๊ตฌ์ฒด์ ์ธ ๋‹จ๊ณ„๋“ค์„ ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ๊ตฌํ˜„ํ•˜๋„๋ก ํ•˜๋Š” ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

์ด ํŒจํ„ด์˜ ํ•ต์‹ฌ์€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๊ตฌ์กฐ๋Š” ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์œผ๋ฉด์„œ, ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ํŠน์ • ๋‹จ๊ณ„๋“ค์„ ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ์žฌ์ •์˜ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๐Ÿ—๏ธ ํŒจํ„ด์˜ ๊ตฌ์กฐ

ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ ํŒจํ„ด์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ตฌ์กฐ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค:

  • AbstractClass (์ถ”์ƒ ํด๋ž˜์Šค): ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ์™€ ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋“ค์„ ์ •์˜
  • ConcreteClass (๊ตฌ์ฒด ํด๋ž˜์Šค): ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋“ค์„ ๊ตฌ์ฒด์ ์œผ๋กœ ๊ตฌํ˜„

๐ŸŽจ ์žฅ์ ๊ณผ ๋‹จ์ 

โœ… ์žฅ์ 

  • ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ ํ–ฅ์ƒ: ๊ณตํ†ต๋œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ตฌ์กฐ๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
  • ์ผ๊ด€์„ฑ ๋ณด์žฅ: ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์ „์ฒด์ ์ธ ํ๋ฆ„์ด ์ผ์ •ํ•˜๊ฒŒ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค
  • ์œ ์ง€๋ณด์ˆ˜ ์šฉ์ด: ๊ณตํ†ต ๋กœ์ง์˜ ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•  ๋•Œ ์ƒ์œ„ ํด๋ž˜์Šค๋งŒ ์ˆ˜์ •ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค

โŒ ๋‹จ์ 

  • ์ƒ์† ์˜์กด์„ฑ: ์ƒ์† ๊ด€๊ณ„์— ๊ฐ•ํ•˜๊ฒŒ ์˜์กดํ•ฉ๋‹ˆ๋‹ค
  • ์œ ์—ฐ์„ฑ ์ œํ•œ: ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๊ตฌ์กฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค

๐ŸšŒ Java ์˜ˆ์ œ: ๋ฒ„์Šค ์šดํ–‰ ์‹œ์Šคํ…œ

๋ฒ„์Šค ์šดํ–‰ ๊ณผ์ •์„ ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ ํŒจํ„ด์œผ๋กœ ๊ตฌํ˜„ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

// ์ถ”์ƒ ํด๋ž˜์Šค: ๋ฒ„์Šค ์šดํ–‰์˜ ํ…œํ”Œ๋ฆฟ ์ •์˜
public abstract class Bus {
    
    // ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ: ๋ฒ„์Šค ์šดํ–‰์˜ ์ „์ฒด์ ์ธ ํ๋ฆ„ ์ •์˜
    public final void operate() {
        startEngine();
        checkSafety();
        announceRoute();
        driveRoute();
        collectFare();
        stopEngine();
    }
    
    // ๊ณตํ†ต ๋ฉ”์„œ๋“œ๋“ค
    private void startEngine() {
        System.out.println("๐Ÿ”ฅ ์—”์ง„์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.");
    }
    
    private void stopEngine() {
        System.out.println("๐Ÿ›‘ ์—”์ง„์„ ์ •์ง€ํ•ฉ๋‹ˆ๋‹ค.");
    }
    
    // ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋“ค - ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ๊ตฌํ˜„
    protected abstract void checkSafety();
    protected abstract void announceRoute();
    protected abstract void driveRoute();
    protected abstract void collectFare();
}

// ์‹œ๋‚ด๋ฒ„์Šค ๊ตฌํ˜„
public class CityBus extends Bus {
    
    @Override
    protected void checkSafety() {
        System.out.println("๐Ÿ” ์‹œ๋‚ด๋ฒ„์Šค ์•ˆ์ „์ ๊ฒ€: ๋ฌธ ์ž‘๋™, ๋ฒจ ์ž‘๋™ ํ™•์ธ");
    }
    
    @Override
    protected void announceRoute() {
        System.out.println("๐Ÿ“ข ๋‹ค์Œ ์ •๋ฅ˜์žฅ์€ ์‹œ์ฒญ์—ญ์ž…๋‹ˆ๋‹ค.");
    }
    
    @Override
    protected void driveRoute() {
        System.out.println("๐ŸšŒ ์‹œ๋‚ด ๋„๋กœ๋ฅผ ์šดํ–‰ํ•ฉ๋‹ˆ๋‹ค.");
    }
    
    @Override
    protected void collectFare() {
        System.out.println("๐Ÿ’ณ ๊ตํ†ต์นด๋“œ๋ฅผ ํƒœ๊ทธํ•ด์ฃผ์„ธ์š”.");
    }
}

// ๊ณ ์†๋ฒ„์Šค ๊ตฌํ˜„
public class ExpressBus extends Bus {
    
    @Override
    protected void checkSafety() {
        System.out.println("๐Ÿ” ๊ณ ์†๋ฒ„์Šค ์•ˆ์ „์ ๊ฒ€: ์ขŒ์„๋ฒจํŠธ, ๋น„์ƒ๊ตฌ ํ™•์ธ");
    }
    
    @Override
    protected void announceRoute() {
        System.out.println("๐Ÿ“ข ์„œ์šธ→๋ถ€์‚ฐ ๊ณ ์†๋ฒ„์Šค์ž…๋‹ˆ๋‹ค.");
    }
    
    @Override
    protected void driveRoute() {
        System.out.println("๐Ÿ›ฃ๏ธ ๊ณ ์†๋„๋กœ๋ฅผ ์šดํ–‰ํ•ฉ๋‹ˆ๋‹ค.");
    }
    
    @Override
    protected void collectFare() {
        System.out.println("๐ŸŽซ ์Šน์ฐจ๊ถŒ์„ ํ™•์ธํ•ด์ฃผ์„ธ์š”.");
    }
}

// ์‚ฌ์šฉ ์˜ˆ์ œ
public class BusExample {
    public static void main(String[] args) {
        System.out.println("=== ์‹œ๋‚ด๋ฒ„์Šค ์šดํ–‰ ===");
        Bus cityBus = new CityBus();
        cityBus.operate();
        
        System.out.println("\n=== ๊ณ ์†๋ฒ„์Šค ์šดํ–‰ ===");
        Bus expressBus = new ExpressBus();
        expressBus.operate();
    }
}

โฐ TypeScript ์˜ˆ์ œ: ์‹œ๊ณ„ ์‹œ์Šคํ…œ

๋‹ค์–‘ํ•œ ์ข…๋ฅ˜์˜ ์‹œ๊ณ„๋ฅผ ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ ํŒจํ„ด์œผ๋กœ ๊ตฌํ˜„ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

// ์ถ”์ƒ ํด๋ž˜์Šค: ์‹œ๊ณ„์˜ ํ…œํ”Œ๋ฆฟ ์ •์˜
abstract class Clock {
    
    // ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ: ์‹œ๊ณ„ ๋™์ž‘์˜ ์ „์ฒด์ ์ธ ํ๋ฆ„ ์ •์˜
    public displayTime(): void {
        this.updateTime();
        this.formatTime();
        this.showDisplay();
        this.playSound();
    }
    
    // ๊ณตํ†ต ๋ฉ”์„œ๋“œ
    private updateTime(): void {
        console.log("โฑ๏ธ ํ˜„์žฌ ์‹œ๊ฐ„์„ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.");
    }
    
    // ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋“ค - ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ๊ตฌํ˜„
    protected abstract formatTime(): void;
    protected abstract showDisplay(): void;
    protected abstract playSound(): void;
}

// ๋””์ง€ํ„ธ ์‹œ๊ณ„ ๊ตฌํ˜„
class DigitalClock extends Clock {
    
    protected formatTime(): void {
        const now = new Date();
        const timeString = now.toLocaleTimeString('ko-KR', { 
            hour12: false,
            hour: '2-digit',
            minute: '2-digit',
            second: '2-digit'
        });
        console.log(`๐Ÿ”ข ๋””์ง€ํ„ธ ํฌ๋งท: ${timeString}`);
    }
    
    protected showDisplay(): void {
        console.log("๐Ÿ’ป LED ๋””์Šคํ”Œ๋ ˆ์ด์— ์‹œ๊ฐ„์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.");
    }
    
    protected playSound(): void {
        console.log("๐Ÿ”Š ์‚์‚์‚! ๋””์ง€ํ„ธ ์•Œ๋žŒ์Œ");
    }
}

// ์•„๋‚ ๋กœ๊ทธ ์‹œ๊ณ„ ๊ตฌํ˜„
class AnalogClock extends Clock {
    
    protected formatTime(): void {
        const now = new Date();
        const hours = now.getHours() % 12;
        const minutes = now.getMinutes();
        console.log(`๐Ÿ• ์•„๋‚ ๋กœ๊ทธ ํฌ๋งท: ${hours}์‹œ ${minutes}๋ถ„`);
    }
    
    protected showDisplay(): void {
        console.log("โš™๏ธ ์‹œ์นจ๊ณผ ๋ถ„์นจ์œผ๋กœ ์‹œ๊ฐ„์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.");
    }
    
    protected playSound(): void {
        console.log("๐Ÿ”” ๋•ก๋•ก๋•ก! ์‹œ๊ณ„ ์ข…์†Œ๋ฆฌ");
    }
}

// ์Šค๋งˆํŠธ์›Œ์น˜ ๊ตฌํ˜„
class SmartWatch extends Clock {
    
    protected formatTime(): void {
        const now = new Date();
        const timeString = now.toLocaleString('ko-KR', {
            year: 'numeric',
            month: '2-digit',
            day: '2-digit',
            hour: '2-digit',
            minute: '2-digit',
            second: '2-digit'
        });
        console.log(`๐Ÿ“ฑ ์Šค๋งˆํŠธ ํฌ๋งท: ${timeString}`);
    }
    
    protected showDisplay(): void {
        console.log("๐Ÿ“บ OLED ํ™”๋ฉด์— ๋‹ค์–‘ํ•œ ์ •๋ณด์™€ ํ•จ๊ป˜ ์‹œ๊ฐ„์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.");
    }
    
    protected playSound(): void {
        console.log("๐ŸŽต ์‚ฌ์šฉ์ž ์ง€์ • ์•Œ๋ฆผ์Œ");
    }
}

// ์‚ฌ์šฉ ์˜ˆ์ œ
class ClockExample {
    static run(): void {
        console.log("=== ๋””์ง€ํ„ธ ์‹œ๊ณ„ ===");
        const digitalClock = new DigitalClock();
        digitalClock.displayTime();
        
        console.log("\n=== ์•„๋‚ ๋กœ๊ทธ ์‹œ๊ณ„ ===");
        const analogClock = new AnalogClock();
        analogClock.displayTime();
        
        console.log("\n=== ์Šค๋งˆํŠธ์›Œ์น˜ ===");
        const smartWatch = new SmartWatch();
        smartWatch.displayTime();
    }
}

// ์‹คํ–‰
ClockExample.run();

๐ŸŽฏ ํ™œ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค

ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ ํŒจํ„ด์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค:

๐Ÿณ ์š”๋ฆฌ ๋ ˆ์‹œํ”ผ ์‹œ์Šคํ…œ

  • ๊ธฐ๋ณธ์ ์ธ ์š”๋ฆฌ ๊ณผ์ •(์ค€๋น„→์กฐ๋ฆฌ→๋งˆ๋ฌด๋ฆฌ)์€ ๋™์ผํ•˜์ง€๋งŒ, ๊ฐ ๋‹จ๊ณ„์˜ ๊ตฌ์ฒด์ ์ธ ๋‚ด์šฉ์ด ๋‹ค๋ฅธ ๊ฒฝ์šฐ

๐Ÿ“Š ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ํŒŒ์ดํ”„๋ผ์ธ

  • ๋ฐ์ดํ„ฐ ์ฝ๊ธฐ→์ฒ˜๋ฆฌ→์ €์žฅ์˜ ํ๋ฆ„์€ ๊ฐ™์ง€๋งŒ, ๊ฐ ๋‹จ๊ณ„์˜ ๊ตฌํ˜„์ด ๋‹ค๋ฅธ ๊ฒฝ์šฐ

๐ŸŽฎ ๊ฒŒ์ž„ ์‹œ์Šคํ…œ

  • ๊ฒŒ์ž„์˜ ๊ธฐ๋ณธ ํ๋ฆ„(์ดˆ๊ธฐํ™”→๊ฒŒ์ž„์ง„ํ–‰→๊ฒฐ๊ณผํ‘œ์‹œ)์€ ๊ฐ™์ง€๋งŒ, ๊ฒŒ์ž„๋งˆ๋‹ค ๊ตฌ์ฒด์ ์ธ ๋กœ์ง์ด ๋‹ค๋ฅธ ๊ฒฝ์šฐ

๐Ÿ’ก ๋งˆ๋ฌด๋ฆฌ

ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ ํŒจํ„ด์€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๋ผˆ๋Œ€๋ฅผ ์ œ๊ณตํ•˜๋ฉด์„œ๋„ ์„ธ๋ถ€ ๊ตฌํ˜„์˜ ์œ ์—ฐ์„ฑ์„ ๋ณด์žฅํ•˜๋Š” ๊ฐ•๋ ฅํ•œ ํŒจํ„ด์ž…๋‹ˆ๋‹ค. ์ฝ”๋“œ์˜ ์ค‘๋ณต์„ ์ค„์ด๊ณ  ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๋ฉด์„œ๋„, ๊ฐ ๊ตฌํ˜„์ฒด๊ฐ€ ์ž์‹ ๋งŒ์˜ ํŠน์„ฑ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค๋‹ˆ๋‹ค.

ํŠนํžˆ ํ”„๋ ˆ์ž„์›Œํฌ ๊ฐœ๋ฐœ์ด๋‚˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค๊ณ„์—์„œ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ํŒจํ„ด์ด๋ฏ€๋กœ, ๊ฐ์ฒด์ง€ํ–ฅ ์„ค๊ณ„์˜ ํ•ต์‹ฌ ๊ฐœ๋… ์ค‘ ํ•˜๋‚˜๋กœ ๊ผญ ์•Œ์•„๋‘์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค! ๐Ÿš€


 

728x90
๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€