Featured image of post 14. 다양한 패턴 빠르게 알아보기 - 브리지 패턴

14. 다양한 패턴 빠르게 알아보기 - 브리지 패턴

헤드 퍼스트 디자인 패턴

브리지(Bridge) 패턴

구현과 더불어 추상화 부분까지 변경해야 한다면 브리지 패턴을 사용한다.

브리지 패턴은 객체 지향 프로그래밍에서 사용되는 디자인 패턴 중 하나로, 추상화와 구현을 분리하여 두 부분이 독립적으로 변화할 수 있도록 하는 구조를 제공한다.

이를 통해 시스템의 확정성을 높이고, 추상화와 구현의 결합도를 낮춘다.

구성 요소

브리지 패턴 구조

  • 추상화(Abstraction)
    • 클라이언트가 사용하는 인터페이스를 정의한다.
    • 추상화는 구현에 대한 참조를 가지며, 클라이언트는 이 추상화를 통해 구현에 접근한다.
  • 구현자(Implementor)
    • 추상화의 구현을 위한 인터페이스를 정의한다.
    • 구현을 위한 메소드들을 선언하는데, 이들 메소드는 구체적인 구현 클래스에서 구현된다.
  • 정제된 추상화(Refined Abstraction)
    • 추상화의 하위 클래스로, 추가적인 기능을 제공하거나 확장할 수 있다.
  • 구현자 구현(Concrete Implementor)
    • Implementor의 구현 클래스로, 실제로 구현이 이루어진다.

예시: 간단한 도형 그리기

이 구현에서는 도형과 그리기 도구가 각각 추상화와 구현을 나타내며, 브리지 패턴을 통해 두 부분을 분리한다.

클라이언트는 도형을 생성하고 원하는 그리기 도구를 지정할 수 있어, 새로운 도형이나 그리기 도구를 추가하더라도 기존 코드에 영향을 덜 주고 시스템을 확장할 수 있다.

Abstraction: 도형

도형을 나타내는 추상 클래스로서, 그리기 도구와 연결됨

1
2
3
4
5
6
7
8
9
public abstract class Shape {
    protected DrawingAPI drawingAPI;

    protected Shape(DrawingAPI drawingAPI) {
        this.drawingAPI = drawingAPI;
    }

    public abstract void draw();
}

Refined Abstraction: Circle 및 Square

도형의 구체적인 형태를 나타내는 클래스로서, 추상화된 도형을 확장한다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class Circle extends Shape {
    private int x, y, radius;

    public Circle(int x, int y, int radius, DrawingAPI drawingAPI) {
        super(drawingAPI);
        this.x = x;
        this.y = y;
        this.radius = radius;
    }

    @Override
    public void draw() {
        drawingAPI.drawCircle(x, y, radius);
    }
}

public class Square extends Shape {
    private int x, y, side;

    public Square(int x, int y, int side, DrawingAPI drawingAPI) {
        super(drawingAPI);
        this.x = x;
        this.y = y;
        this.side = side;
    }

    @Override
    public void draw() {
        drawingAPI.drawSquare(x, y, side);
    }
}

Implementor: DrawingAPI

그리기 도구를 나타내는 인터페이스로서, 실제 구현은 구체적인 구현 클래스에서 이루어진다.

1
2
3
4
public interface DrawingAPI {
  void drawCircle(int x, int y, int radius);
  void drawSquare(int x, int y, int side);
}

Concrete Implementor: DrawingAPI1 및 DrawingAPI2

DrawingAPI를 구현한 구체적인 클래스로서, 실제로 그리기 동작을 수행

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class DrawingAPI1 implements DrawingAPI {
    @Override
    public void drawCircle(int x, int y, int radius) {
        System.out.println("API1 - Drawing Circle at (" + x + ", " + y + ") with radius " + radius);
    }

    @Override
    public void drawSquare(int x, int y, int side) {
        System.out.println("API1 - Drawing Square at (" + x + ", " + y + ") with side " + side);
    }
}

public class DrawingAPI2 implements DrawingAPI {
    @Override
    public void drawCircle(int x, int y, int radius) {
        System.out.println("API2 - Drawing Circle at (" + x + ", " + y + ") with radius " + radius);
    }

    @Override
    public void drawSquare(int x, int y, int side) {
        System.out.println("API2 - Drawing Square at (" + x + ", " + y + ") with side " + side);
    }
}

특징

장점

  1. 분리된 추상화와 구현
  • 추상화와 구현을 분리하여 두 부분이 독립적으로 변화할 수 있다록 한다.
  • 이를 통해 코드의 확장성과 유지보수성을 향상시킬 수 있다.
  1. 유연한 확장
  • 새로운 추상화나 구현을 추가하는 데 있어 기존 코드에 영향을 최소화 할 수 있다.
  • 새로운 기능이나 클래스를 도입할 때 유연하게 대응할 수 있다.
  1. 복잡성 감소
  • 각각의 변경이 다른 부분에 미치는 영향을 최소화하므로 코드를 이해하고 유지보수하는 데 도움을 줄 수 있다.
  1. 다형성 강화
  • 추상화와 구현 사이의 느슨한 결합을 제공하므로, 다양한 형태의 추상화와 구현을 조합하여 사용할 수 있다.

단점

  1. 복잡성 증가
    • 추가적인 클래스와 인터페이스를 도입하여 시스템을 구현하므로, 간단한 시스템에서는 과도한 복잡성을 초래할 수 있다.
  2. 설계 과정에서 추가 비용
    • 초기 설계 단계에서 브리지 패턴을 도입하는 데 추가적인 비용이 발생할 수 있다.
    • 특히 간단한 시스템에서는 이를 도입하는 것이 과도할 수 있다.
  3. 인터페이스 수 증가
  • 구현자와 추상화에 대한 인터페이스가 각각 존재하므로, 클래스 수가 증가할 수 있다.
  • 이로 인해 코드 베이스의 관리를 어렵게 할 수 있다.

정리

브리지 패턴은 시스템이 확장이나 변경이 빈번하게 발생하는 경우에 유용하지만 간단한 시스템에서는 추가적인 복잡성이나 비용이 필요할 수 있으므로 상황에 맞게 적용해야한다.