💡 브릿지 패턴이란
큰 클래스 또는 밀접하게 관련된 클래스들의 집합을 두 개의 개별 계층 구조(추상화 및 구현)로 나눈 후
각각 독립적으로 개발할 수 있도록 하는 구조 디자인 패턴입니다.
브릿지 패턴은 상속에서 객체의 합성으로 전환하여 위 문제를 해결합니다.
즉, 차원 중 하나를 별도의 클래스 계층 구조로 추출하여 원래 클래스들이 한 클래스 내에서
모든 상태와 행동들을 갖는 대신 새 계층 구조의 객체를 참조하도록 하는 것입니다.
여기서 모양 클래스는 색상 객체들 중 하나를 가리키는 참조 필드를 받습니다.
이제 모양은 연결된 색상 객체에 모든 색상 관련 작업을 위임할 수 있습니다.
이 참조는 이제부터 모양 및 색상 클래스들 사이의 Bridge(다리) 역할을 하게 됩니다.
이제 새 색상들을 추가할 때 모양 계층 구조를 변경할 필요가 없으며 그 반대도 마찬가지가 됩니다.
💡 브릿지 패턴 기본 구조
객체의 확장성을 향상하기 위한 패턴으로, 객체에서 동작을 처리하는 구현부와 확장을 위한 추상부로 분리합니다.
브릿지 패턴은 기능의 클래스 계층과 구현의 클래스 계층을 연결하고, 구현부에서 추상 계층을 분리하여
추상화된 부분과 실제 구현 부분을 독립적으로 확장할 수 있는 디자인 패턴입니다.
1. Abstraction (추상화)
상위 수준의 제어 논리를 제공하며, 구현 객체에 의존해 실제 하위 수준 작업들을 수행합니다.
2. Implementation (구현)
모든 구상 구현들에 공통적인 인터페이스를 선언하며,
추상화는 여기 선언된 메서드들을 통해서만 구현 객체와 소통할 수 있습니다.
추상화는 구현과 같은 메서드들을 나열할 수 있지만,
보통 구현이 선언한 다양한 원시 작업들에 의존하는 몇 가지 복잡한 행동들을 선언합니다.
3. Concrete Implementations (구체적 구현체들)
플랫폼 별 맞춤형 실제 기능이 구현된 코드가 포함됩니다.
4. Refined Abstractions (정제된 추상화들)
제어 논리의 변형들을 제공합니다. 추상부 계층에서 새로운 부분을 확장한 클래스입니다.
5. Client
Client는 추상화 작업하는데에만 관심이 있습니다.
그러나 추상화 객체를 구현 객체들 중 하나와 연결하는 것도 클라이언트의 역할입니다.
💡 브릿지 패턴 구현 예제
아래 예시는 모양(Shape)과 색깔(Color)을 추상화와 구현 부분으로 분리하였습니다.
1. Abstraction, Refined Abstractions (추상화, 정제된 추상화들)
// 추상화 부분 - 모양
interface Shape {
void draw(Color color);
}
// 구체적인 모양 구현
class Circle implements Shape {
private int x, y, radius;
public Circle(int x, int y, int radius) {
this.x = x;
this.y = y;
this.radius = radius;
}
@Override
public void draw(Color color) {
color.applyColor(x, y);
System.out.println("Drawing a circle at (" + x + "," + y + ") with radius " + radius);
}
}
class Rectangle implements Shape {
private int x, y, width, height;
public Rectangle(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
@Override
public void draw(Color color) {
color.applyColor(x, y);
System.out.println("Drawing a rectangle at (" + x + "," + y + ") with width " + width + " and height " + height);
}
}
2. Implementation, Concrete Implementations (구현, 구체적 구현체들)
// 구현 부분 - 색깔
interface Color {
void applyColor(int x, int y);
}
// 구체적인 색깔 구현
class Red implements Color {
@Override
public void applyColor(int x, int y) {
System.out.println("Applying red color at (" + x + "," + y + ")");
}
}
class Blue implements Color {
@Override
public void applyColor(int x, int y) {
System.out.println("Applying blue color at (" + x + "," + y + ")");
}
}
3. Client
// 클라이언트 코드
public class BridgePatternDemo {
public static void main(String[] args) {
Shape circle = new Circle(2, 3, 5);
circle.draw(new Red());
circle.draw(new Blue());
Shape rectangle = new Rectangle(4, 5, 6, 7);
rectangle.draw(new Blue());
rectangle.draw(new Red());
}
}
클라이언트 코드는 구현 객체를 추상화의 생성자에 전달하여 이 객체를 그 생성자에 연관시켜야 합니다.
그 후에 클라이언트는 구현을 잊어버린 후 추상화 객체와만 작업할 수 있습니다.
💡 결론
브릿지 패턴은 클래스에서 구현과 추상 2개의 계층으로 분리할 수 있고 독립적인 확장이 가능합니다.
이는 기존 시스템에 부수적인 새로운 기능들을 지속적으로 추가할 때 사용하면 유용한 패턴입니다.
다만, 추상화를 통해 코드를 분리할 경우 코드 디자인 설계가 복잡해질 수 있고,
결합도가 높은 클래스 패턴을 적용하여 코드를 더 복잡하게 만들 수 있습니다.
참조 자료