hongcheol / CS-study

cs지식을 정리하는 공간
MIT License
248 stars 30 forks source link

브릿지 패턴 #134

Open Baemung opened 3 years ago

Baemung commented 3 years ago

Bridge

image

Bridge 패턴이란?

큰 클래스 또는 밀접하게 관련된 클래스 집합을 서로 독립적으로 개발할 수 있도록 두 개의 계층(기능 계층과 구현 계층)으로 분리한 디자인 패턴이다.

구현부에서 추상층을 분리하여 각자 독립적으로 변형이 가능하고 확장이 가능하도록 한다. 즉 기능과 구현에 대해서 두 개를 별도의 클래스로 구현을 한다.

image

먼저 브릿지 패턴이 왜 필요한지 알아보자.

Problem

Shape라는 클래스가 CircleSquare라는 2개의 서브클래스를 가진다고 가정해보자.

이 클래스 구조에서 각각 RedBlue 라는 Color를 적용시켜 Shape에 Color를 통합, 확장시키려고 한다.

이미 Shape에는 CircleSquare라는 하위 클래스가 있으므로, 위 이미지와 같이 BlueCircleRedSquare와 같이 네 개의 클래스 조합을 만들어야 한다.

만약 계속 이런 방식으로 클래스를 확장해 나가서 Shape가 100개, Color가 100개가 된다면 10,000개의 클래스가 필요하게 된다.

이 후 Shape이나, Color를 1개라도 추가시키려면 각 Shape별 혹은 Color별 클래스가 100개씩 추가시키는 작업이 필요하게 되는 것은 큰 문제이다.

이러한 문제를 해결하는 디자인 패턴이 바로 브릿지 패턴이다.

Solution

위와 같은 문제는 Shape 클래스를 Shape별, Color별 독립적으로 확장하려고 하기 때문에 발생하는 문제인데, 이러한 문제는 계급 상속과 관련된 매우 흔한 문제라고 할 수 있다.

브릿지 패턴은 객체 합성으로 이 문제를 해결한다. 한 클래스 내에 모든 상태나 동작을 포함하는 것이 아닌 아래의 이미지와 같이 원래의 클래스가 새로 확장하려는 상태를 클래스로 분리하여 해당 클래스를 참조하여 조합을 만드는 것이다.

image

Bridge 패턴 구조

image

Bridge 패턴 구현

image

RemoteControl.class


public class RemoteControl {
private Device divice;
public RemoteControl(Device divice){
     this.divice = divice;
}

public void togglePower() {
     if(divice.isEnabled()) divice.disable();
     else divice.enable();
}

public void volumeDown {
     device.setVolume(device.getVolume() - 10);
}

public void volumeUp {
     device.setVolume(device.getVolume() + 10);
}

public void channelDown {
     device.setChannel(device.getChannel() - 1);
}

public void channelUp {
     device.setChannel(device.getChannel() + 1);
}

}


> AdvancedRemoteControl.class
```java
public class AdvancedRemoteControl extends RemoteControl {
    public void mute() {
         device.setVolume(0);
    }
}

Device.interface

public interface Device {
public boolean isEnabled();
public void enable();
public void disable();
public int getVolume();
public void setVolume(int percent);
public int getChannel();
public void setChannel(int channel);
}

Radio.class


public class Radio implements Device {
private int volume = 50, channel = 11;
private boolean isEnabled;
public boolean isEnabled(){
     return this.isEnabled
}
public void enable(){
     this.isEnabled = true;
}
public void disable(){
     this.isEnabled = false;
}
public int getVolume(){
     return this.volume;
}
public void setVolume(int volume){
     this.volume = volume;
}
public int getChannel(){
     return this.channel;
}
public void setChannel(int channel){
     this.channel = channel;
}

}


> TV.class
```java
public class TV implements Device{
    private int volume, channel;
    private boolean isEnabled;

    public boolean isEnabled(){
         return this.isEnabled
    }
    public void enable(){
         this.isEnabled = true;
    }
    public void disable(){
         this.isEnabled = false;
    }
    public int getVolume(){
         return this.volume;
    }
    public void setVolume(int volume){
         this.volume = volume;
    }
    public int getChannel(){
         return this.channel;
    }
    public void setChannel(int channel){
         this.channel = channel;
    }
}

Main.class


public class Main {
public static void main(String argsp[])
{    
tv = new Tv()
remote = new RemoteControl(tv);
remote.togglePower();
     radio = new Radio();
     remote = new AdvancedRemoteControl(radio);
}

}



흔히 `Adapter` 패턴과 `Bridge` 패턴을 헷갈려하는 경우가 많다고 한다. 

`Adapter` 패턴은 **서로 다른 인터페이스(API)를 연결해주는 패턴**이라면, 

`Bridge` 패턴은 **구현 계층과 기능(추상) 계층을 서로 분리, 연결시켜주는 패턴**이다.

### Bridge 패턴의 활용
- 여러 플랫폼에서 사용해야 할 그래픽스 및 윈도우 처리 시스템에서 유용하게 쓰인다.
- 인터페이스와 실제 구현부를 서로 다른 방식으로 변경해야 하는 경우에 유용하게 쓰인다.

### Bridge 패턴의 장점
- 조합의 개수가 늘어남으로써 발생하는 기하급수적인 클래스 확장을 막을 수 있다.
- 구현을 인터페이스에 완전히 결합시키지 않았기 때문에 구현과 추상화된 부분을 분리시킬 수 있다.
- 추상화된 부분과 실제 구현 부분을 독립적으로 확장할 수 있습니다.
- 추상화된 부분을 구현한 구상 클래스를 바꿔도 클라이언트 쪽에는 영향을 끼치지 않는다.

### Bridge 패턴의 단점
- 응집도가 높은 클래스에 적용하면 코드와 디자인이 더 복잡해진다는 단점이 있다.

---

Reference : [https://refactoring.guru/design-patterns/bridge](https://refactoring.guru/design-patterns/bridge)