PostCover

디자인 패턴을 쉽게 풀어보자 - 브릿지 패턴편

GoF의 23가지 디자인 패턴 중 하나인 '브릿지 패턴(Bridge Pattern)'을 쉽게 풀어보기

브릿지(Bridge) 패턴

브리지 패턴은 구현부와 추상부를 분리하여 독립적으로 확장할 수 있도록 설계하는 구조적 디자인 패턴입니다. 이 패턴은 기능 계층과 구현 계층을 분리해 결합도를 낮추고 확장성을 높여줍니다.

문제점: 기능과 구현의 결합

애플리케이션에서 다양한 기능과 구현 방법을 동시에 처리해야 할 때, 클래스가 기하급수적으로 증가하는 문제가 발생합니다. 예를 들어, 다양한 색상의 모양(원, 사각형 등)을 구현한다고 할 때, 색상과 모양의 조합만큼 클래스를 생성해야 합니다.

// 다양한 색상과 모양을 구현해야 할 경우
class RedCircle {
    public void draw() {
        System.out.println("Drawing Red Circle");
    }
}

class BlueCircle {
    public void draw() {
        System.out.println("Drawing Blue Circle");
    }
}

class RedSquare {
    public void draw() {
        System.out.println("Drawing Red Square");
    }
}

class BlueSquare {
    public void draw() {
        System.out.println("Drawing Blue Square");
    }
}

// 클라이언트 코드
public class Main {
    public static void main(String[] args) {
        RedCircle redCircle = new RedCircle();
        redCircle.draw();

        BlueSquare blueSquare = new BlueSquare();
        blueSquare.draw();
    }
}

문제점

  • 클래스 폭발 문제: 색상과 모양의 조합이 많아지면 클래스 수가 기하급수적으로 증가합니다.
  • 유연성 부족: 색상이나 모양을 수정하려면 각각의 조합에 대해 코드를 수정해야 합니다.
  • 유지보수 어려움: 새로운 색상이나 모양이 추가될 때 모든 조합을 다시 정의해야 합니다.

해결 방법: 브리지 패턴 적용

브리지 패턴은 **기능 계층(추상부)**과 **구현 계층(구체부)**를 분리해 각각 독립적으로 확장할 수 있도록 합니다. 이 패턴을 사용하면 기능의 확장과 구현의 확장이 서로 간섭하지 않습니다.

Implementation 정의

// 색상 인터페이스
interface Color {
    String fill();
}

// 구체적인 색상 구현
class Red implements Color {
    @Override
    public String fill() {
        return "Color is Red";
    }
}

class Blue implements Color {
    @Override
    public String fill() {
        return "Color is Blue";
    }
}

Abstraction 정의

// 모양 추상 클래스
abstract class Shape {
    protected Color color;  // 구현부와 연결

    public Shape(Color color) {
        this.color = color;
    }

    public abstract void draw();
}

구체적인 추상부 구현

// 원 모양 클래스
class Circle extends Shape {
    public Circle(Color color) {
        super(color);
    }

    @Override
    public void draw() {
        System.out.println("Drawing Circle with " + color.fill());
    }
}

// 사각형 모양 클래스
class Square extends Shape {
    public Square(Color color) {
        super(color);
    }

    @Override
    public void draw() {
        System.out.println("Drawing Square with " + color.fill());
    }
}

클라이언트 코드

public class Main {
    public static void main(String[] args) {
        // 원을 빨간색으로 그리기
        Shape redCircle = new Circle(new Red());
        redCircle.draw();  // Drawing Circle with Color is Red

        // 사각형을 파란색으로 그리기
        Shape blueSquare = new Square(new Blue());
        blueSquare.draw();  // Drawing Square with Color is Blue
    }
}

브리지 패턴의 장단점

장점

  • 확장성: 기능과 구현을 독립적으로 확장할 수 있습니다. 예를 들어, 새로운 색상이나 모양을 추가해도 기존 클래스를 수정할 필요가 없습니다.
  • 유지보수 용이: 기능과 구현이 분리되어 있어 각 부분을 쉽게 수정할 수 있습니다.
  • 코드 중복 제거: 기능과 구현 계층을 분리하여 중복 코드를 줄일 수 있습니다.
  • 의존성 감소: 기능 계층과 구현 계층이 강하게 결합되지 않으므로 결합도가 낮아집니다.

단점

  • 복잡성 증가: 추상 계층과 구현 계층을 분리해야 하므로 코드가 복잡해질 수 있습니다.
  • 클래스 수 증가: 기능과 구현을 각각 클래스로 정의해야 하므로 클래스의 수가 늘어날 수 있습니다.

결론

브리지 패턴은 기능과 구현을 분리하여 유연성과 확장성을 높이는 데 유용한 패턴입니다. 이 패턴을 사용하면 기능과 구현이 독립적으로 변경될 수 있어 유지보수가 쉬워집니다. 하지만 추상화와 구현을 분리하는 과정에서 코드의 복잡성이 증가할 수 있으므로, 복잡한 기능을 가진 애플리케이션에서 사용하기 적합합니다.