Bridge Pattern
리모컨을 나타내는 클래스를 구현한다고 해보자.
리모컨들은 TV 브랜드마다 내부적으로는 다르게 동작해야하기 때문에 각 TV 브랜드에 적합하게 구현할 필요가 있다.
이 때 일차원적으로 생각해보면 RemoteControl이라는 인터페이스로 일단 한 번 추상화하고 각 TV 브랜드에 맞게 구체 클래스를 작성할 수 있다.
요구사항이 더 이상 발생하지 않는다면 다행이지만, 리모컨 기능이라는 추상화 부분이 변경되면 어떻게 될까? 일반 리모컨과 추가 기능이 포함된 특별한 리모컨으로 나누어진다면 아래와 같이 6개의 구체 클래스가 생성될 것이다.
GenericSonyRemoteControlGenericSamsungRemoteControlGenericLGRemoteContolSpecialSonyRemoteControlSpecialSamsungRemoteControlSpecialLGRemoteContol
이렇게되면 얼핏 봐도 유지보수가 쉽지 않아 보인다. 브릿지 패턴은 추상화된 부분(리모컨의 기능)과 구현 부분(각 TV 브랜드에 맞는 구현)을 composition을 사용하여 분리하고, 이들이 각각 독립적으로 확장해 나갈 수 있도록하는 패턴이다.
패턴 적용
위 예제에서는 TV에 해당하는 구현 부분을 composition으로 분리해낸다.
public abstract class TV {
public abstract void on();
public abstract void off();
public abstract void tuneChannel(int channel);
public abstract int getChannel();
}
----------------------------
public class TVFactory {
public TV getTV(String type) throws Exception {
if (type.equals("LG")) {
return new LG();
} else if (type.equals("Samsung")) {
return new Samsung();
} else if (type.equals("Sony")) {
return new Sony();
} else {
throw new Exception("Invalid TV Type");
}
}
}
----------------------------
public class Sony extends TV {
int station = 0;
public void on() {
System.out.println("Turning on the Sony TV");
}
public void off() {
System.out.println("Turning off the Sony TV");
}
public void tuneChannel(int channel) {
this.station = channel;
System.out.println("Set the Sony TV station to " + this.station);
}
public int getChannel() {
return station;
}
}
----------------------------
public class Samsung extends TV {
int station = 0;
public void on() {
System.out.println("Turning on the Samsung TV");
}
public void off() {
System.out.println("Turning off the Samsung TV");
}
public void tuneChannel(int channel) {
this.station = channel;
System.out.println("Set the Samsung TV station to " + this.station);
}
public int getChannel() {
return station;
}
}
----------------------------
public class LG extends TV {
int channel = 1;
public void on() {
System.out.println("Turning on the LG TV");
}
public void off() {
System.out.println("Turning off the LG TV");
}
public void tuneChannel(int channel) {
this.channel = channel;
System.out.println("Set the LG TV Channel to " + this.channel);
}
public int getChannel() {
return channel;
}
}public abstract class RemoteControl {
TV tv;
TVFactory tvFactory;
public RemoteControl(TVFactory tvFactory) {
this.tvFactory = tvFactory;
}
public void on() {
this.tv.on();
}
public void off() {
this.tv.off();
}
public void setChannel(int channel) {
tv.tuneChannel(channel);
}
public int getChannel() {
return tv.getChannel();
}
public void setTV(String type) {
try {
tv = tvFactory.getTV(type);
} catch (Exception e) {
System.out.println(e);
}
}
}
----------------------------
public class GenericRemote extends RemoteControl {
public GenericRemote(TVFactory tvFactory) {
super(tvFactory);
}
public void nextChannel() {
int channel = this.getChannel();
this.setChannel(channel+1);
}
public void prevChannel() {
int channel = this.getChannel();
this.setChannel(channel-1);
}
}
----------------------------
public class SpecialRemote extends RemoteControl {
public SpecialRemote(TVFactory tvFactory) {
super(tvFactory);
}
public void up() {
int channel = this.getChannel();
this.setChannel(channel+1);
}
public void down() {
int channel = this.getChannel();
this.setChannel(channel-1);
}
}참고
- 에릭 프리먼, 엘리자베스 롭슨, 키이시 시에라, 버트 베이츠, 헤드 퍼스트 디자인 패턴, 서환수, 한빛미디어