728x90
"서로 독립적인 기능 계층과 구현 계층을 분리하고 싶을 때!"
- 브릿지 패턴은 "기능(Abstraction)과 구현(Implementation)을 독립적으로 확장할 수 있도록 설계하는 패턴"
- "하나의 기능이 다양한 구현을 가질 때" 매우 유용함
- 클래스 수가 증가할 수 있으므로, 불필요하게 적용하지 않도록 주의해야 함
📌 브릿지 패턴의 핵심 개념
- 추상화 (Abstraction)
- 인터페이스 또는 추상 클래스로, 클라이언트가 사용하게 될 주요 기능을 정의함
- 구현부(Implementation)와 연결(Bridge)되어 있어, 기능을 전달
- 구현부 (Implementation)
- 실제 구현을 담당하는 인터페이스 또는 클래스
- 추상화된 클래스에서 호출하여 기능을 실행
- 추상화(Refined Abstraction)
- Abstraction을 확장한 구체적인 클래스
- 구체적인 구현부 (Concrete Implementation)
- Implementation을 구체적으로 구현한 클래스
📌 브릿지 패턴의 동작 방식
- Abstraction 클래스는 Implementation 인터페이스를 참조하여, 실제 구현을 호출함
- Implementation 인터페이스를 구현한 여러 개의 ConcreteImplementation 클래스를 만들어 다형성을 지원
- Abstraction을 확장한 RefinedAbstraction 클래스를 추가하여, 보다 구체적인 기능을 제공할 수 있음
📌 브릿지 패턴의 UML
+---------------------+
| Abstraction | <----------------+
|---------------------| |
| - impl: Implementor | |
| + operation() | |
+---------------------+ |
| |
| |
+------------------+ +----------------------+
| Implementor |<>------>| ConcreteImplementorA |
|------------------| +----------------------+
| + operationImp() | | 실제 기능 구현 코드 |
+------------------+ +----------------------+
|
+----------------------+
| ConcreteImplementorB |
+----------------------+
| 실제 기능 구현 코드 |
+----------------------+
📌 브릿지 패턴 예제 코드 (Java)
1. Implementor 인터페이스 정의
// 구현부(Implementation) 역할
interface Device {
void turnOn();
void turnOff();
}
2. ConcreteImplementor 클래스
// Concrete Implementor A
class TV implements Device {
@Override
public void turnOn() {
System.out.println("TV가 켜졌습니다.");
}
@Override
public void turnOff() {
System.out.println("TV가 꺼졌습니다.");
}
}
// Concrete Implementor B
class Radio implements Device {
@Override
public void turnOn() {
System.out.println("라디오가 켜졌습니다.");
}
@Override
public void turnOff() {
System.out.println("라디오가 꺼졌습니다.");
}
}
3. Abstraction 클래스
// Abstraction 역할
abstract class RemoteControl {
protected Device device;
public RemoteControl(Device device) {
this.device = device;
}
abstract void turnOn();
abstract void turnOff();
}
4. RefinedAbstraction 클래스
// Refined Abstraction 역할 (구체적인 리모컨 유형)
class BasicRemoteControl extends RemoteControl {
public BasicRemoteControl(Device device) {
super(device);
}
@Override
void turnOn() {
System.out.print("리모컨: ");
device.turnOn();
}
@Override
void turnOff() {
System.out.print("리모컨: ");
device.turnOff();
}
}
5. 사용 예시
public class BridgePatternExample {
public static void main(String[] args) {
Device tv = new TV();
Device radio = new Radio();
RemoteControl tvRemote = new BasicRemoteControl(tv);
RemoteControl radioRemote = new BasicRemoteControl(radio);
tvRemote.turnOn(); // 리모컨: TV가 켜졌습니다.
tvRemote.turnOff(); // 리모컨: TV가 꺼졌습니다.
radioRemote.turnOn(); // 리모컨: 라디오가 켜졌습니다.
radioRemote.turnOff(); // 리모컨: 라디오가 꺼졌습니다.
}
}
출력 결과:
리모컨: TV가 켜졌습니다.
리모컨: TV가 꺼졌습니다.
리모컨: 라디오가 켜졌습니다.
리모컨: 라디오가 꺼졌습니다.
📌 브릿지 패턴의 장단점
✅ 장점
- 확장성 증가
- Abstraction과 Implementation을 독립적으로 확장 가능
- 예를 들어, 리모컨 유형을 추가하거나, 새로운 디바이스(TV, Radio 등)를 추가 가능
- 코드 재사용성 증가
- 같은 Implementation을 여러 Abstraction에서 재사용 가능
- 코드 중복을 줄이고 유지보수가 쉬워짐
- OCP(Open-Closed Principle) 준수
- 새로운 기능을 추가할 때 기존 클래스를 변경하지 않고 확장할 수 있음
❌ 단점
- 구조가 복잡해질 수 있음
- 단순한 경우에는 적용할 필요가 없으며, 오히려 클래스가 불필요하게 많아질 수 있음
- 객체의 수 증가
- Abstraction과 Implementation을 분리하면서 클래스를 추가해야 하므로, 클래스 수가 증가할 수 있음
📌 브릿지 패턴을 사용해야 할 때
✅ 적합한 경우
- 하나의 기능이 다양한 구현을 가질 때 (예: 리모컨 → TV / 라디오)
- 두 개의 개념(기능과 구현)을 독립적으로 변경해야 할 때
- 유지보수가 용이하고 확장성이 높은 구조를 원할 때
❌ 적합하지 않은 경우
- 단순한 계층 구조일 경우
- 클래스 분리가 필요하지 않고, 인터페이스만으로도 충분할 경우
📌 브릿지 패턴이 사용되는 예시
- GUI 프레임워크
- 버튼(Button)을 만들고, 그 구현(WindowsButton, LinuxButton)을 분리
- JDBC (Java Database Connectivity)
- DriverManager(Abstraction)와 JDBC Driver(Implementation)를 분리
- 그래픽 렌더링 시스템
- Shape(추상화)와 DrawingAPI(구현)을 분리하여 다양한 렌더링 기법을 지원
728x90
'디자인 패턴' 카테고리의 다른 글
Decorator Pattern (0) | 2024.05.05 |
---|---|
Composite Pattern (1) | 2024.05.01 |
Command Pattern (0) | 2024.04.28 |
Chain Of Responsibility Pattern (0) | 2024.04.27 |
Adapter Pattern (0) | 2024.04.10 |