디자인패턴

[디자인패턴] 파사드패턴 & 전략패턴

개바리여리 2025. 9. 29. 23:02

Facade 패턴

복잡한 서브시스템(여러 클래스나 모듈)을 **간단한 인터페이스(파사드)**로 감싸서 클라이언트가 쉽게 사용할 수 있게 해주는 구조 패턴.

다수로 구성되는 서브 시스템을 하나로 묶어주는 Facade 클래스가 존재하는 형태이다.

// 서브시스템 1: 엔진
class Engine {
    public void start() {
        System.out.println("엔진 가동");
    }
}

// 서브시스템 2: 연료펌프
class FuelPump {
    public void pump() {
        System.out.println("연료 공급");
    }
}

// 서브시스템 3: 배터리
class Battery {
    public void supplyPower() {
        System.out.println("배터리 전원 공급");
    }
}

// 서브시스템 4: 점화장치
class Ignition {
    public void ignite() {
        System.out.println("점화 장치 작동");
    }
}

// 파사드 (Facade)
class CarFacade {
    private Engine engine;
    private FuelPump fuelPump;
    private Battery battery;
    private Ignition ignition;

    public CarFacade() {
        this.engine = new Engine();
        this.fuelPump = new FuelPump();
        this.battery = new Battery();
        this.ignition = new Ignition();
    }

    public void startCar() {
        System.out.println("=== 자동차 시동 프로세스 시작 ===");
        battery.supplyPower();
        fuelPump.pump();
        ignition.ignite();
        engine.start();
        System.out.println("=== 자동차 시동 완료 ===");
    }
}

 

자동차 시동을 거는 과정은 여러 단계가 필요해요.

  • 연료 공급 → 엔진 점화 → 배터리 체크 → 시동 모터 구동

클라이언트가 이 모든 클래스를 직접 호출하면 복잡해진다.
 CarFacade를 두어 클라이언트는 startCar()만 호출하면 된다

이렇게 함으로써 클라이언트는 세부 클래스가 무엇인지 몰라도 원하는 구성을 가져와서 구현할 수 있다.

 

전략 패턴 (Strategy Pattern)

특정 작업을 하는 방식(전략)을 여럿 두고 필요에 따라 런타임 환경에 갈아끼울 수 있는 패턴이다.

행위를 캡슐화하여 필요할 때 교체 가능하게 만드는 패턴

 

 

  • Context(문맥): 전략을 사용하는 쪽 → 실행 시점에 어떤 전략을 쓸지 선택.
  • Strategy(전략 인터페이스): 공통된 동작 규약을 정의.
  • ConcreteStrategy(구체 전략): 실제 알고리즘/로직을 구현.

if-else 대신 전략 객체를 갈아끼워서 유연성을 확보하는 구조이다.

 

// 전략 인터페이스
interface PaymentStrategy {
    void pay(int amount);
}

// 구체적인 전략들
class CreditCardPayment implements PaymentStrategy {
    private String name;
    private String cardNumber;

    CreditCardPayment(String name, String cardNumber) {
        this.name = name;
        this.cardNumber = cardNumber;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount + "원을 " + name + "의 CreditCard(" + cardNumber + ")로 지불");
    }
}

class PayPalPayment implements PaymentStrategy {
    private String email;

    PayPalPayment(String email) {
        this.email = email;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount + "원을 PayPal(" + email + ")로 지불");
    }
}

// Context (전략을 사용하는 쪽)
class ShoppingCart {
    private PaymentStrategy paymentStrategy;

    // 전략을 바꿀 수 있도록 set 메서드 제공
    public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }

    public void checkout(int amount) {
        if (paymentStrategy == null) {
            System.out.println("결제 수단이 선택되지 않았습니다.");
        } else {
            paymentStrategy.pay(amount);
        }
    }
}

// 실행
public class Main {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();

        // 전략을 신용카드로 설정
        cart.setPaymentStrategy(new CreditCardPayment("홍길동", "1111-2222-3333-4444"));
        cart.checkout(10000);

        // 전략을 PayPal로 변경
        cart.setPaymentStrategy(new PayPalPayment("user@example.com"));
        cart.checkout(20000);
    }
}

 

 

해당 방식은 새로운 방식이 추가되어야 한다면 또 다른 전략 클래스를 만들어 쉽게 확장가능하고

다른 곳에 재사용 하는것도 가능하게 된다.

어떻게 보면 개방-폐쇄 원칙을 준수하는 코드도 작성 할 수 있게 된다.