디자인 패턴

Bridge Pattern

kyoulho 2024. 4. 10. 13:42
728x90

"서로 독립적인 기능 계층과 구현 계층을 분리하고 싶을 때!"

  • 브릿지 패턴은 "기능(Abstraction)과 구현(Implementation)을 독립적으로 확장할 수 있도록 설계하는 패턴"
  • "하나의 기능이 다양한 구현을 가질 때" 매우 유용함
  • 클래스 수가 증가할 수 있으므로, 불필요하게 적용하지 않도록 주의해야 함

📌 브릿지 패턴의 핵심 개념

  1. 추상화 (Abstraction)
    • 인터페이스 또는 추상 클래스로, 클라이언트가 사용하게 될 주요 기능을 정의함
    • 구현부(Implementation)와 연결(Bridge)되어 있어, 기능을 전달
  2. 구현부 (Implementation)
    • 실제 구현을 담당하는 인터페이스 또는 클래스
    • 추상화된 클래스에서 호출하여 기능을 실행
  3. 추상화(Refined Abstraction)
    • Abstraction을 확장한 구체적인 클래스
  4. 구체적인 구현부 (Concrete Implementation)
    • Implementation을 구체적으로 구현한 클래스

📌 브릿지 패턴의 동작 방식

  • Abstraction 클래스는 Implementation 인터페이스를 참조하여, 실제 구현을 호출함
  • Implementation 인터페이스를 구현한 여러 개의 ConcreteImplementation 클래스를 만들어 다형성을 지원
  • Abstraction을 확장한 RefinedAbstraction 클래스를 추가하여, 보다 구체적인 기능을 제공할 수 있음

📌 브릿지 패턴의 UML

      +---------------------+
      |  Abstraction        | <----------------+
      |---------------------|                  |
      | - impl: Implementor |                  |
      | + operation()       |                  |
      +---------------------+                  |
               |                               |
               |                               |
      +------------------+         +----------------------+
      |  Implementor     |<>------>| ConcreteImplementorA |
      |------------------|         +----------------------+
      | + operationImp() |         | 실제 기능 구현 코드      |
      +------------------+         +----------------------+
               |
      +----------------------+
      | ConcreteImplementorB |
      +----------------------+
      | 실제 기능 구현 코드      |
      +----------------------+

📌 브릿지 패턴 예제 코드 (Java)

1. Implementor 인터페이스 정의

// 구현부(Implementation) 역할
interface Device {
    void turnOn();
    void turnOff();
}

2. ConcreteImplementor 클래스

// Concrete Implementor A
class TV implements Device {
    @Override
    public void turnOn() {
        System.out.println("TV가 켜졌습니다.");
    }

    @Override
    public void turnOff() {
        System.out.println("TV가 꺼졌습니다.");
    }
}

// Concrete Implementor B
class Radio implements Device {
    @Override
    public void turnOn() {
        System.out.println("라디오가 켜졌습니다.");
    }

    @Override
    public void turnOff() {
        System.out.println("라디오가 꺼졌습니다.");
    }
}

3. Abstraction 클래스

// Abstraction 역할
abstract class RemoteControl {
    protected Device device;

    public RemoteControl(Device device) {
        this.device = device;
    }

    abstract void turnOn();
    abstract void turnOff();
}

4. RefinedAbstraction 클래스

// Refined Abstraction 역할 (구체적인 리모컨 유형)
class BasicRemoteControl extends RemoteControl {
    public BasicRemoteControl(Device device) {
        super(device);
    }

    @Override
    void turnOn() {
        System.out.print("리모컨: ");
        device.turnOn();
    }

    @Override
    void turnOff() {
        System.out.print("리모컨: ");
        device.turnOff();
    }
}

5. 사용 예시

public class BridgePatternExample {
    public static void main(String[] args) {
        Device tv = new TV();
        Device radio = new Radio();

        RemoteControl tvRemote = new BasicRemoteControl(tv);
        RemoteControl radioRemote = new BasicRemoteControl(radio);

        tvRemote.turnOn();  // 리모컨: TV가 켜졌습니다.
        tvRemote.turnOff(); // 리모컨: TV가 꺼졌습니다.

        radioRemote.turnOn();  // 리모컨: 라디오가 켜졌습니다.
        radioRemote.turnOff(); // 리모컨: 라디오가 꺼졌습니다.
    }
}

출력 결과:

리모컨: TV가 켜졌습니다.
리모컨: TV가 꺼졌습니다.
리모컨: 라디오가 켜졌습니다.
리모컨: 라디오가 꺼졌습니다.

📌 브릿지 패턴의 장단점

장점

  1. 확장성 증가
    • Abstraction과 Implementation을 독립적으로 확장 가능
    • 예를 들어, 리모컨 유형을 추가하거나, 새로운 디바이스(TV, Radio 등)를 추가 가능
  2. 코드 재사용성 증가
    • 같은 Implementation을 여러 Abstraction에서 재사용 가능
    • 코드 중복을 줄이고 유지보수가 쉬워짐
  3. OCP(Open-Closed Principle) 준수
    • 새로운 기능을 추가할 때 기존 클래스를 변경하지 않고 확장할 수 있음

단점

  1. 구조가 복잡해질 수 있음
    • 단순한 경우에는 적용할 필요가 없으며, 오히려 클래스가 불필요하게 많아질 수 있음
  2. 객체의 수 증가
    • Abstraction과 Implementation을 분리하면서 클래스를 추가해야 하므로, 클래스 수가 증가할 수 있음

📌 브릿지 패턴을 사용해야 할 때

적합한 경우

  • 하나의 기능이 다양한 구현을 가질 때 (예: 리모컨 → TV / 라디오)
  • 두 개의 개념(기능과 구현)을 독립적으로 변경해야 할 때
  • 유지보수가 용이하고 확장성이 높은 구조를 원할 때

적합하지 않은 경우

  • 단순한 계층 구조일 경우
  • 클래스 분리가 필요하지 않고, 인터페이스만으로도 충분할 경우

📌 브릿지 패턴이 사용되는 예시

  1. GUI 프레임워크
    • 버튼(Button)을 만들고, 그 구현(WindowsButton, LinuxButton)을 분리
  2. JDBC (Java Database Connectivity)
    • DriverManager(Abstraction)와 JDBC Driver(Implementation)를 분리
  3. 그래픽 렌더링 시스템
    • Shape(추상화)와 DrawingAPI(구현)을 분리하여 다양한 렌더링 기법을 지원
728x90

'디자인 패턴' 카테고리의 다른 글

Decorator Pattern  (0) 2024.05.05
Composite Pattern  (1) 2024.05.01
Command Pattern  (0) 2024.04.28
Chain Of Responsibility Pattern  (0) 2024.04.27
Adapter Pattern  (0) 2024.04.10