1. 브릿지 패턴 정의
구현부에서 추상층을 분리하여 각자 독립적으로 변형할 수 있게 하는 패턴이다.
브릿지 패턴 (Bridge Pattern)
객체의 구현부(implementation)와 추상층(abstraction)을 분리하여 각각 독립적으로 변형할 수 있게 하는 구조적인 디자인 패턴 중 하나이다. 이 패턴은 서로 독립된 두 개의 계층이 서로 연결되어 동작하게 하는 것을 중점으로 한다.
'bridge' 란 '다리' 라는 의미로 다음의 두 장소에서 연결하는 역할을 한다.
- 기능의 클래스 계층
- 구현의 클래스 계층
각 구성요소의 설명
- Client: Client는 Abstraction코드를 사용하는 주체이다.
- Abstraction: Abstraction은 추상적인 로직을 담고 있는 클래스 이다.
- Refined Abstraction: Abstraction의 다양한 변형체이고 이 자체가 하나의 또 다른 하나의 계층구조로 확장해 내려갈 수 있다.
- Implementation: 구체적인 정보를 담고 있습니다. 상태, 액션, 플랫폼에 특화되어 있는 코드와 같은 것들을 담고 있는 클래스이다.
- Concrete Implementation: Implementation의 또 다른 Implementation을 가지고 별도의 계층구조로 발전시킬 수 있는 클래스이다.
활용 상황
- 런타임에 실제로 사용될 구체적인 구현체가 결정되어야 할때 유용합니다.
- 구현할 클래스의 기능부 및 구현부가 지속적인 확장 가능성이 있을때 유용합니다.
Bridge 패턴의 장단점
장점
- 추상화된 인터페이스와 구현된 클래스를 분리하여 유연한 확장이 가능하다. 새로운 클래스를 추가하거나 변경할 때, 기존 코드를 수정하지 않고도 새로운 클래스와 연결하여 쉽게 확장할 수 있게 해준다.
- 코드의 재사용성을 높여준다. 구현된 클래스와 추상화된 인터페이스를 분리하여 구현 클래스를 재사용하거나 다른 구현 클래스와 연결하여 쉽게 재사용할 수 있습니다.
- 코드의 가독성을 높여준다. 추상화된 인터페이스와 구현된 클래스를 분리하여 코드의 의미를 명확하게 전달할 수 았다.
단점
- 코드의 복잡성이 증가한다. 브리지 패턴을 구현하려면 클래스 간의 연결이 필요하므로 코드의 복잡성이 증가할 수 있다.
- 추상화된 인터페이스와 구현된 클래스를 분리하는 것이 코드의 중복을 일으킬 수 있다. 구현된 클래스 간의 공통점이 많은 경우 추상화된 인터페이스와 구현된 클래스를 분리하는 것이 중복된 코드를 일으킬 수 있다.
- 브리지 패턴을 적용하면 런타임에 객체가 생성되므로 약간의 성능 저하가 발생할 수 있다. 하지만 대부분의 상황에서는 성능에 큰 영향을 미치지 않는다.
예제 코드
원격제어와 가전제품
RemoteControl(원격제어) 라는 클래스와 Device 라는 클래스를 사용하여 다양한 종류의 원격제어 바식과 가전제품을 조합
// Implementor (Device 인터페이스)
interface Device {
void turnOn();
void turnOff();
void setVolume(int percent);
boolean isOn();
}
// Concrete Implementor (구체적인 가전제품 클래스)
class TV implements Device {
private boolean on = false;
private int volume = 50;
public void turnOn() {
on = true;
System.out.println("TV is turned on.");
}
public void turnOff() {
on = false;
System.out.println("TV is turned off.");
}
public void setVolume(int percent) {
this.volume = percent;
System.out.println("TV volume set to " + percent + "%.");
}
public boolean isOn() {
return on;
}
}
class Radio implements Device {
private boolean on = false;
private int volume = 50;
public void turnOn() {
on = true;
System.out.println("Radio is turned on.");
}
public void turnOff() {
on = false;
System.out.println("Radio is turned off.");
}
public void setVolume(int percent) {
this.volume = percent;
System.out.println("Radio volume set to " + percent + "%.");
}
public boolean isOn() {
return on;
}
}
// Abstraction (RemoteControl 추상 클래스)
abstract class RemoteControl {
protected Device device;
public RemoteControl(Device device) {
this.device = device;
}
abstract void power();
abstract void volumeUp();
abstract void volumeDown();
}
// Refined Abstraction (구체적인 리모컨 클래스)
class BasicRemote extends RemoteControl {
public BasicRemote(Device device) {
super(device);
}
public void power() {
if (device.isOn()) {
device.turnOff();
} else {
device.turnOn();
}
}
public void volumeUp() {
device.setVolume(60);
}
public void volumeDown() {
device.setVolume(40);
}
}
class AdvancedRemote extends RemoteControl {
public AdvancedRemote(Device device) {
super(device);
}
public void power() {
if (device.isOn()) {
device.turnOff();
} else {
device.turnOn();
}
}
public void volumeUp() {
device.setVolume(80);
}
public void volumeDown() {
device.setVolume(20);
}
public void mute() {
device.setVolume(0);
System.out.println("Device is muted.");
}
}
// 클라이언트 코드
public class BridgePatternExample {
public static void main(String[] args) {
Device tv = new TV();
RemoteControl basicRemote = new BasicRemote(tv);
basicRemote.power();
basicRemote.volumeUp();
Device radio = new Radio();
RemoteControl advancedRemote = new AdvancedRemote(radio);
advancedRemote.power();
advancedRemote.volumeUp();
((AdvancedRemote)advancedRemote).mute();
}
}
- Abstraction(추상화): RemoteControl 클래스는 원격 제어의 공통 인터페이스를 정의
- Refined Abstraction(구체적인 추상화): BasicRemote(기본 리모컨), AdvancedRemote(고급 리모컨)과 같은 구체적인 원격 제어 클래스들이 RemoteControl 클래스를 상속
- Implementor(구현자): Device 인터페이스는 가전제품을 정의하는 메서드를 제공
- Concrete Implementor(구체적인 구현자): TV, Radio와 같은 클래스들이 Device 인터페이스를 구현하여 실제 가전제품을 정의
출력 결과
TV is turned on.
TV volume set to 60%.
Radio is turned on.
Radio volume set to 80%.
Device is muted.
- RemoteControl(리모컨)과 Device(가전제품)는 서로 독립적으로 확장 가능. 새로운 리모컨이나 새로운 가전제품을 추가할 때, 기존 클래스에 영향을 주지 않음.
- 브릿지 역할: RemoteControl 클래스는 Device 인터페이스를 통해 실제 가전제품과의 연결을 담당하며, 다양한 리모컨 방식에 대한 구현과 가전제품 제어를 분리.
- 유연성: 이 패턴을 통해 기본 리모컨과 고급 리모컨을 같은 가전제품에 적용할 수 있고, 새로운 리모컨과 가전제품을 쉽게 추가할 수 있다.
브리지 패턴을 사용하면 기존의 코드를 변경하지 않고도 새로운 기능을 추가하거나 수정할 수 있기때문에 유지보수성이 우수해집니다. 또한 코드의 재사용성을 높여 개발 시간과 비용을 절감할 수 있습니다. 하지만 구현할 때 클래스 간의 결합도를 최소화하면서도 추상화와 구현의 분리를 유지하는 것이 중요 하다고 생각 합니다. 그렇지 않으면 코드의 복잡성이 증가할 수 있고, 중복된 코드가 발생할 수 있게 됩니다. 따라서 구현할 기능이 복잡하거나 확장성과 유지보수성을 고려해야 하는 경우에 적절하게 사용해야 합니다.