브릿지 패턴이란?
브리지 패턴(Bridge Pattern)은 추상화와 구현을 분리하여, 서로 독립적으로 변형할 수 있도록 하는 구조적인 패턴입니다. 브리지 패턴을 이용하면, 기능과 구현을 별도로 관리할 수 있으며, 객체 간의 결합도를 낮출 수 있습니다. 브리지 패턴에서는 추상화와 구현을 각각 클래스로 구현합니다. 추상화는 구현에 의존하지만, 구현은 추상화에 의존하지 않습니다. 이렇게 구현을 추상화로부터 분리함으로써, 두 요소를 독립적으로 변경할 수 있습니다.
브리지 패턴은 구현에 대한 확장성과 유연성을 제공합니다. 새로운 구현을 추가하거나, 기존 구현을 변경해도, 추상화와 관련된 코드를 변경하지 않아도 됩니다. 따라서, 유지보수성과 확장성이 높아집니다.
브리지 패턴은 다른 패턴과 함께 사용되기도 합니다. 예를 들어, 브리지 패턴과 추상 팩토리 패턴을 결합하여, 추상화와 구현을 분리하면서도 새로운 객체를 생성할 수 있습니다. 브리지 패턴의 예시로는, 모바일 디바이스에서 UI 테마를 변경하는 경우가 있습니다. 모바일 디바이스에서 UI 테마는 구현에 해당하며, UI 요소는 추상화에 해당합니다. 따라서, 브리지 패턴을 이용하여 UI 요소와 UI 테마를 분리하여 독립적으로 변경할 수 있습니다.
브리지 패턴은 객체 간의 결합도를 낮추고, 유지보수성과 확장성을 높일 수 있습니다. 따라서, 다른 패턴과 함께 사용되어 더욱 강력한 솔루션을 제공할 수 있습니다.
브릿지 패턴의 구성 요소
위의 설명대로 브릿지 패턴을 구현하기 위한 구성 요소를 나누면 다음과 같습니다.
- 추상화 : 구현에 독립적인 인터페이스를 정의합니다.
- 추상화 상속 : 추상화를 상속받아 구체적인 기능을 제공합니다.
- 구현: 구현에 대한 인터페이스를 정의합니다.
- 구체적인 구현: 구현을 실제로 구현합니다.
한국어로 하면 단어가 조금 어색합니다. 직접 만들면서 알아보는게 더욱 와닿을 것이므로, 이 구성요소를 사용해 브릿지 패턴을 JavaScript를 사용해 직접 구현해보겠습니다.
브릿지 패턴 JavaScript로 구현해보기
먼저 추상화된 Shape이라는 이름의 인터페이스를 만듭니다. JavaScript는 인터페이스를 공식적으로 지원하지 않으므로 class로 만듭니다.
*이 Shape은 구성요소인 '구현'과 상관 없이 독립적인 인터페이스입니다. 즉 '구현'에서는 이 인터페이스를 사용하지 않습니다.
// Abstraction (추상화)
class Shape {
constructor(color) {
this.color = color;
}
draw() {}
}
이후 추상화된 클래스를 상속받아 구체적인 기능을 만들어 냅니다.
// 추상화 상속
class Circle extends Shape {
constructor(x, y, radius, color) {
super(color);
this.x = x;
this.y = y;
this.radius = radius;
}
draw() {
console.log(`Drawing circle with color ${this.color} at (${this.x},${this.y}) with radius ${this.radius}`);
}
}
'구현' 인터페이스인 DrawingAPI를 만듭니다.
// Implementor (구현)
class DrawingAPI {
drawCircle(x, y, radius) {}
}
'구현' 인터페이스 DrawingAPI를 상속하는 두가지 API용 클래스를 만들어냅니다. 이를 '구현의 구현' 이라고 부릅니다. 각 버전의 DrawingAPI는 모두 DrawingAPI를 상속해 drawCircle을 구현합니다. 이 '구현의 구현'은 위의 Circle 인터페이스를 참조하지 않고 있음을 볼 수 있습니다.
// Concrete Implementor (구체적인 구현)
class V1DrawingAPI extends DrawingAPI {
drawCircle(x, y, radius) {
console.log(`V1DrawingAPI - Drawing circle at (${x},${y}) with radius ${ radius}`);
}
}
// Concrete Implementor (구체적인 구현)
class V2DrawingAPI extends DrawingAPI {
drawCircle(x, y, radius) {
console.log(`V2DrawingAPI - Drawing circle at (${x},${y}) with radius ${radius}`);
}
}
이렇게 만들어진 구현체는 다음과 같이 사용처에 의해 참고됩니다. 여기서 CircleShape은 앞에서 만든 '추상화'인 Shape을 구현하는 '추상화 구현'인 Circle과 '구현'인 DrawingAPI를 구현하는 '구현의 구현'을 생성자로 받아 객체 내부에 저장해 draw() 메서드에서 사용합니다.
// Usage
class CircleShape {
constructor(x, y, radius, color, drawingAPI) {
this.shape = new Circle(x, y, radius, color);
this.drawingAPI = drawingAPI;
}
draw() {
this.drawingAPI.drawCircle(this.shape.x, this.shape.y, this.shape.radius);
}
}
이렇게 CircleShape을 만들면 Shape을 구현하는 클래스를 DrawingAPI와 독립적으로 만들 수 있습니다.
브릿지 패턴 정리 하기
용어가 조금 많이 헷갈려서 어렵겠지만 브릿지 패턴의 중요한 점은 바로 두개의 인터페이스가 서로 간에 독립적으로 동작하도록 하는 것입니다. 위에서는 Shape과 DrawingAPI와의 의존성을 사라지게 만듬으로써 이 둘 사이의 의존성을 사라지게 만들면 한쪽이 바뀌더라도 다른 한쪽에 영향이 없도록 할 수 있어 새로운 구현을 쉽게 추가하도록 할 수 있습니다. 하지만 위에서 보았듯이 코드의 복잡도가 많이 증가합니다.
브릿지 패턴은 추상화와 구현을 분리함으로써, 객체 간의 결합도를 낮추고, 코드의 유연성을 향상시킵니다. 이를 통해, 새로운 구현을 쉽게 추가하고, 기존 구현을 변경할 수 있습니다. 하지만, 구현과 추상화를 분리하면서, 클래스의 수가 증가할 수 있으며, 코드의 복잡도가 증가할 수도 있습니다.
따라서, 브릿지 패턴은 구현이 변할 가능성이 높은 경우나, 구현과 추상화를 분리해야 하는 경우에만 한정적으로 사용해야 합니다. 예를 들어, UI 테마와 UI 요소를 분리하여 독립적으로 변경해야 하는 경우에 브릿지 패턴을 사용할 수 있습니다.
장단점을 정리하면 아래와 같습니다.
장점
추상화와 구현을 분리하므로, 객체 간의 결합도를 낮출 수 있습니다.
추상화와 구현을 독립적으로 변경할 수 있습니다.
새로운 구현을 쉽게 추가할 수 있습니다.
코드의 유연성을 향상시킵니다.
단점
- 구현과 추상화를 분리하면서, 클래스의 수가 증가할 수 있습니다.
- 코드의 복잡도가 증가할 수 있습니다.
'JavaScript 디자인 패턴' 카테고리의 다른 글
[JavaScript 디자인 패턴] 어댑터 패턴이란 무엇인가? 어댑터 패턴 사용해 서로 다른 인터페이스 연결하기 (0) | 2023.02.27 |
---|---|
[JavaScript 디자인 패턴] 구조 패턴이란 무엇인가? 구조 패턴의 특징과 종류에 대해 알아보자 (0) | 2023.02.26 |
[JavaScript 디자인 패턴] 프로토 타입 패턴 : 객체를 복사해 새로운 객체를 생성하는 패턴 (0) | 2023.02.24 |
[JavaScript 디자인 패턴] 싱글톤 패턴: 장단점과 구현 방법 알아보기 (0) | 2023.02.22 |
[JavaScript 디자인 패턴] 생성 패턴이란 무엇인가? 생성 패턴의 장단점과 종류 알아보기 (0) | 2023.02.21 |