Bridge Pattern 완벽 정리

테사벨로그·2025년 12월 3일

Design Pattern

목록 보기
19/19

1. 숲 보기 (Concept Flow)

1단계: 문제 상황 (The Problem - Combinatorial Explosion)

상황: 그래픽 프로그램에서 여러 종류의 도형(Shape)을 여러 종류의 드로잉 라이브러리(DP1, DP2)로 그려야 한다. 상속만으로 해결하려 하면 추상화(Abstraction)구현(Implementation)이 강하게 결합되어 클래스가 기하급수적으로 증가한다.

핵심 문제: M개의 도형 × N개의 드로잉 라이브러리 = M×N개의 클래스 필요

Bad Code Example:

// 상속만 사용한 접근법 - 조합의 폭발 (Combinatorial Explosion)
abstract class Shape { abstract void draw(); }

abstract class Rectangle extends Shape { /* drawLine 추상 메서드 */ }
abstract class Circle extends Shape { /* drawCircle 추상 메서드 */ }

// 2개 도형 × 2개 구현 = 4개 클래스 (새 도형/구현 추가 시 급증!)
class V1Rectangle extends Rectangle { /* DP1 사용 */ }
class V2Rectangle extends Rectangle { /* DP2 사용 */ }
class V1Circle extends Circle { /* DP1 사용 */ }
class V2Circle extends Circle { /* DP2 사용 */ }

// 만약 DP3이 추가되면? → V3Rectangle, V3Circle 추가 필요
// 만약 Triangle이 추가되면? → V1Triangle, V2Triangle, V3Triangle 추가 필요

2단계: 해결책 (The Solution - Bridge Pattern)

접근: 추상화 계층(Abstraction Hierarchy)구현 계층(Implementation Hierarchy)을 분리하고, 객체 합성(Composition)으로 연결한다.

핵심 원리:

  • "Find what varies and encapsulate it" (변하는 것을 찾아 캡슐화하라)
  • "Favor object composition over class inheritance" (상속보다 합성을 선호하라)

분석 과정:

분석 유형대상결과
Commonality Analysis (공통성)Shape, Drawing추상 클래스로 표현
Variability Analysis (가변성)Rectangle/Circle, V1/V2Drawing구체 클래스로 구현

Good Code Example:

// Abstraction(추상화)이 Implementor(구현자)를 참조로 가짐
abstract class Shape {
    private Drawing _dp; // Bridge: 구현 객체에 대한 참조
    
    Shape(Drawing dp) { _dp = dp; }
    
    abstract public void draw();
    
    // 구현 객체에 작업을 위임(Delegation)
    protected void drawLine(double x1, double y1, double x2, double y2) {
        _dp.drawLine(x1, y1, x2, y2);
    }
    protected void drawCircle(double x, double y, double r) {
        _dp.drawCircle(x, y, r);
    }
}

// Client 코드: 런타임에 추상화와 구현을 독립적으로 조합
Drawing dp = new V1Drawing();
Shape rect = new Rectangle(dp, 1, 1, 2, 2);
rect.draw(); // 어떤 Drawing을 사용하는지 Shape은 알 필요 없음

3단계: 결과 및 평가 (Pros & Cons)

장점:

  • 클래스 수 선형 증가: M×N → M+N (도형 3개 + 구현 3개 = 6개 클래스)
  • 독립적 확장: 새 도형이나 새 드로잉 라이브러리를 서로 영향 없이 추가 가능 (OCP 준수)
  • 구현 세부사항 은닉: 클라이언트는 Shape 인터페이스만 알면 됨
  • 런타임 구현 교체: 실행 중에도 구현 객체를 교체할 수 있음

단점:

  • 초기 설계 복잡도 증가: 사전에 추상화/구현 분리를 계획해야 함
  • 간접 호출로 인한 약간의 성능 오버헤드

2. 키워드 계층 구조도 (Keyword Hierarchy Map with Java)

  • Bridge Pattern (구조 패턴 - Structural Pattern)

    • 1. Abstraction (추상화)

      • 역할: 추상화 계층의 인터페이스를 정의하고, Implementor에 대한 참조를 유지
      • Java Code:
        abstract class Shape {
            private Drawing _dp; // Implementor 참조 (Bridge)
            
            Shape(Drawing dp) { _dp = dp; }
            
            abstract public void draw(); // 클라이언트가 호출할 인터페이스
            
            // Implementor에 작업 위임
            protected void drawLine(double x1, double y1, double x2, double y2) {
                _dp.drawLine(x1, y1, x2, y2);
            }
        }
      • 구현 원리: Implementor를 멤버 변수로 가지며, 실제 작업을 위임(Delegation)함
    • 2. RefinedAbstraction (정제된 추상화)

      • 역할: Abstraction의 인터페이스를 확장하여 구체적인 기능 구현

      • Java Code:

        class Rectangle extends Shape {
            private double _x1, _y1, _x2, _y2;
            
            public Rectangle(Drawing dp, double x1, double y1, double x2, double y2) {
                super(dp); // Implementor 전달
                _x1 = x1; _y1 = y1; _x2 = x2; _y2 = y2;
            }
            
            public void draw() {
                // 부모 클래스의 위임 메서드 사용 (실제 구현은 모름)
                drawLine(_x1, _y1, _x2, _y1);
                drawLine(_x2, _y1, _x2, _y2);
                drawLine(_x2, _y2, _x1, _y2);
                drawLine(_x1, _y2, _x1, _y1);
            }
        }
        
        class Circle extends Shape {
            private double _x, _y, _r;
            
            public Circle(Drawing dp, double x, double y, double r) {
                super(dp);
                _x = x; _y = y; _r = r;
            }
            
            public void draw() {
                drawCircle(_x, _y, _r);
            }
        }
      • 특징: 어떤 Drawing 구현을 사용하는지 전혀 알지 못함

    • 3. Implementor (구현자 인터페이스)

      • 역할: 구현 클래스들의 공통 인터페이스 정의 (low-level 작업)
      • Java Code:
        abstract class Drawing {
            abstract public void drawLine(double x1, double y1, double x2, double y2);
            abstract public void drawCircle(double x, double y, double r);
        }
      • 핵심: Abstraction의 인터페이스와 다를 수 있음 (더 primitive한 연산 제공)
    • 4. ConcreteImplementor (구체적 구현자)

      • 역할: Implementor 인터페이스를 실제로 구현 (플랫폼별 구현)

      • Java Code:

        class V1Drawing extends Drawing {
            public void drawLine(double x1, double y1, double x2, double y2) {
                DP1.draw_a_line(x1, y1, x2, y2); // DP1 라이브러리 사용
            }
            public void drawCircle(double x, double y, double r) {
                DP1.draw_a_circle(x, y, r);
            }
        }
        
        class V2Drawing extends Drawing {
            public void drawLine(double x1, double y1, double x2, double y2) {
                DP2.drawline(x1, x2, y1, y2); // DP2는 파라미터 순서가 다름!
            }
            public void drawCircle(double x, double y, double r) {
                DP2.drawcircle(x, y, r);
            }
        }
      • 특징: 각 플랫폼/라이브러리의 API 차이를 내부에서 처리

    • 5. Client (클라이언트)

      • 역할: Abstraction과 Implementor를 조합하여 사용
      • Java Code:
        public class Client {
            public static void main(String[] args) {
                Drawing dp1 = new V1Drawing();
                Drawing dp2 = new V2Drawing();
                
                Shape r1 = new Rectangle(dp1, 1, 1, 2, 2); // DP1으로 그리는 사각형
                Shape c1 = new Circle(dp2, 2, 2, 3);       // DP2로 그리는 원
                
                r1.draw();
                c1.draw();
            }
        }

3. Comparative Analysis: 비교 분석

Bridge vs Adapter

비교 항목Bridge PatternAdapter Pattern
목적 (Intent)추상화와 구현을 분리하여 독립적 확장 가능하게 함호환되지 않는 인터페이스를 변환하여 함께 동작하게 함
적용 시점설계 초기(up-front)에 적용하여 확장성 확보설계 후(after) 기존 시스템에 적용 (리엔지니어링)
구조적 차이복잡한 엔티티의 추상화/구현 계층을 분리단일 인터페이스만 변환
관계추상화가 구현을 참조로 가짐 (Has-a)어댑터가 어댑티를 감싸거나 상속
// Bridge: 설계 시 미리 분리
Shape shape = new Rectangle(new V1Drawing(), ...); // 추상화 + 구현 조합

// Adapter: 기존 시스템 통합
OldSystem oldSys = new OldSystem();
NewInterface adapter = new OldSystemAdapter(oldSys); // 인터페이스 변환

Bridge vs Strategy

비교 항목Bridge PatternStrategy Pattern
분류구조 패턴 (Structural)행동 패턴 (Behavioral)
목적추상화와 구현의 영구적 분리알고리즘의 런타임 교체
계층 구조추상화 쪽도 계층을 가질 수 있음Context는 보통 단일 클래스
의미론"구현 방식"의 분리"행동/전략"의 캡슐화

상속만 사용 vs Bridge 패턴 사용

비교 항목상속만 사용Bridge 패턴 사용
클래스 수M × N (기하급수적)M + N (선형)
결합도추상화-구현 강결합추상화-구현 약결합
확장성새 차원 추가 시 모든 조합 필요독립적으로 확장 가능
바인딩 시점컴파일 타임런타임

4. 기말고사 적중 예상 문제

유형 1: OX 퀴즈

문제 1. Bridge 패턴은 객체의 생성을 담당하는 '생성 패턴(Creational Pattern)'에 속한다.

정답: X
해설: Bridge 패턴은 구조 패턴(Structural Pattern)이다. 클래스와 객체의 구성(composition)을 다룬다.

문제 2. Bridge 패턴에서 Abstraction은 Implementor를 상속받아 구현한다.

정답: X
해설: Abstraction은 Implementor를 멤버 변수로 참조(Has-a)하며, 상속이 아닌 합성(Composition)위임(Delegation)을 사용한다.

문제 3. Bridge 패턴을 사용하면 추상화 계층과 구현 계층을 런타임에 독립적으로 확장할 수 있다.

정답: O
해설: Bridge 패턴의 핵심 목적은 추상화와 구현을 분리하여 독립적으로 확장할 수 있게 하는 것이다.


유형 2: 정의 문제

문제. 다음 설명에 해당하는 디자인 패턴의 이름은?

"추상화(Abstraction)를 구현(Implementation)으로부터 분리하여 둘이 독립적으로 변할 수 있게 한다."

정답: Bridge Pattern
해설: Bridge 패턴의 GoF 정의이다. 추상화 계층과 구현 계층을 별도의 클래스 계층으로 분리하고, 합성을 통해 연결한다.


[유형 3: 시나리오 꼬리물기] (1세트 - 4단계)

[상황] 메시지 발송 시스템을 설계하려 한다. 메시지의 종류로는 TextMessage, EmailMessage가 있고, 발송 플랫폼으로는 SMSSender, PushSender가 있다. 새로운 메시지 종류나 발송 플랫폼이 추가될 예정이다.


3-1. 패턴 선택: 이 상황에 가장 적합한 디자인 패턴은?

정답: Bridge Pattern
해설: 메시지 종류(추상화)와 발송 플랫폼(구현)이라는 두 개의 독립적인 변화 축이 존재하므로 Bridge 패턴이 적합하다. 상속만 사용하면 2×2=4개, 3×3=9개로 클래스가 급증한다.


3-2. 구조 설계: 클래스 구조를 텍스트로 설명하시오.

정답:

  • Abstraction: Message (추상 클래스) - MessageSender를 멤버로 가짐
  • RefinedAbstraction: TextMessage, EmailMessage - Message를 상속
  • Implementor: MessageSender (인터페이스/추상 클래스) - send(String content) 메서드 정의
  • ConcreteImplementor: SMSSender, PushSender - MessageSender 구현

3-3. 구현: TextMessage 클래스의 send() 메서드를 구현하시오. (부모 클래스에 MessageSender sender 멤버가 있다고 가정)

정답:

class TextMessage extends Message {
    private String text;
    
    public TextMessage(MessageSender sender, String text) {
        super(sender);
        this.text = text;
    }
    
    public void send() {
        // 구현 객체에 위임
        sender.send("[TEXT] " + text);
    }
}

3-4. Client 코드: SMS로 텍스트 메시지를 발송하는 객체를 생성하는 한 줄짜리 Java 코드를 작성하시오.

정답:

Message msg = new TextMessage(new SMSSender(), "Hello Bridge!");

유형 4: 필수 개념 심화

문제. Bridge 패턴에서 "Abstraction"과 프로그래밍 언어의 "abstract class"는 같은 개념인가? 그렇지 않다면 Bridge 패턴에서 말하는 Abstraction의 의미를 설명하시오.

정답: 같은 개념이 아니다.

해설:

  • 프로그래밍 언어의 abstract class: 인스턴스화할 수 없고 서브클래스에서 구현해야 하는 추상 메서드를 가진 클래스
  • Bridge 패턴의 Abstraction: 고수준 제어 계층(high-level control layer)을 의미한다. 실제 작업을 직접 수행하지 않고, 구현 계층(Implementation/Platform)에 작업을 위임한다.

예를 들어, Shape(Abstraction)는 "사각형을 그린다"라는 고수준 개념을 표현하고, Drawing(Implementor)은 "선을 긋는다"라는 저수준 primitive 작업을 제공한다. 이 둘은 독립적으로 확장 가능하며, 반드시 Java의 abstract class로 구현될 필요는 없다 (interface로도 가능).


핵심 정리 요약

┌─────────────────────┐         ┌─────────────────────┐
│   Abstraction       │         │    Implementor      │
│   (Shape)           │◇───────▶│    (Drawing)        │
│   +draw()           │   has-a │   +drawLine()       │
│   #drawLine()       │         │   +drawCircle()     │
└─────────┬───────────┘         └─────────┬───────────┘
          │                               │
          │ extends                       │ extends
          ▼                               ▼
┌─────────────────────┐         ┌─────────────────────┐
│ RefinedAbstraction  │         │ ConcreteImplementor │
│ (Rectangle, Circle) │         │ (V1Drawing,V2Drawing│
└─────────────────────┘         └─────────────────────┘

핵심: 추상화와 구현을 분리 → 클래스 수 M×N → M+N
profile
다들 응원합니다.

0개의 댓글