[디자인패턴] 브리지 패턴(Bridge Pattern)

Damsul·2023년 1월 26일
0

디자인패턴

목록 보기
13/15
post-thumbnail

큰 클래스 또는 밀접하게 관련된 클래스들의 집합을 두 개의 개별 계층구조(추상화 및 구현)로 나눈 후 각각 독립적으로 개발할 수 있도록 하는 구조 패턴

출처 : 위키디피아

  • Abstraction : 기능 계층의 최상위 클래스로, 기능을 정의한 인터페이스
  • RefinedAbstraction : Abstraction 인터페이스를 확장한 클래스
  • Implementor : Abstraction의 기능을 구현하기 위한 인터페이스
  • ConcreteImplementor : Implementor 인터페이스를 구현한 클래스

예제

tv와 radio를 리모컨으로 동작 가능하도록 기능을 확장한다고 가정해보자. 추상화(기능) 클래스를 확장하여 리모컨 동작 기능을 추가하고, 기존에 구현한 device와 연결해주어야 한다

  • Implementor

[Device.java]

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);
}
  • ConcreteImplementor

[Tv.java]

public class Tv implements Device {

    boolean flag;
    int volume;
    int channel;

    @Override
    public boolean isEnabled() {
        return flag;
    }

    @Override
    public void enable() {
        ystem.out.println("Tv On");
        flag = true;
    }

    @Override
    public void disable() {
        ystem.out.println("Tv On");
        flag = false;
    }

    @Override
    public int getVolume() {
        return volume;
    }

    @Override
    public void setVolume(int percent) {
        this.volume = percent;
        System.out.println("Tv volume : " + volume);
    }

    @Override
    public int getChannel() {
        return channel;
    }

    @Override
    public void setChannel(int channel) {
        this.channel = channel;
        System.out.println("Tv channel : " + channel);
    }
}

[Radio.java]

public class Radio implements Device {
    boolean flag;
    int volume;
    int channel;

    @Override
    public boolean isEnabled() {
        return flag;
    }

    @Override
    public void enable() {
        System.out.println("Radio On");
        flag = true;
    }

    @Override
    public void disable() {
        System.out.println("Radio On");
        flag = false;
    }

    @Override
    public int getVolume() {
        return volume;
    }

    @Override
    public void setVolume(int percent) {
        this.volume = percent;
        System.out.println("Radio volume : " + volume);
    }

    @Override
    public int getChannel() {
        return channel;
    }

    @Override
    public void setChannel(int channel) {
        this.channel = channel;
        System.out.println("Radio channel : " + channel);
    }
}
  • Abstraction

[RemoteController.java]

public class RemoteController {

    Device device;

    public RemoteController(Device device) {
        this.device = device;
    }

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

    public void volumeDown() {
        if (device.getVolume() - 10 < 0) {
            device.setVolume(0);
        } else {
            device.setVolume(device.getVolume() - 10);
        }
    }

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

    public void channelDown() {
        if (device.getChannel() - 1 < 0) {
            device.setChannel(0);
        } else {
            device.setChannel(device.getChannel() - 1);
        }
    }

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

[AdvancedRemoteController.java]

public class AdvancedRemoteController extends RemoteController{

    public AdvancedRemoteController(Device device) {
        super(device);
    }

    public void mute() {
        super.device.setVolume(0);
    }
}
  • Client

[Client.java]

public class Client {
    public static void main(String[] args) {
        Device tv = new Tv();
        RemoteController tvRemoteController = new AdvancedRemoteController(tv);

        tvRemoteController.togglePower();
        tvRemoteController.togglePower();
        tvRemoteController.volumeDown();
        tvRemoteController.volumeUp();
        tvRemoteController.channelUp();
        tvRemoteController.channelDown();

        System.out.println("===============");

        Device radio = new Radio();
        AdvancedRemoteController radioRemoteController = new AdvancedRemoteController(radio);

        radioRemoteController.togglePower();
        radioRemoteController.togglePower();
        radioRemoteController.volumeDown();
        radioRemoteController.volumeUp();
        radioRemoteController.channelDown();
        radioRemoteController.channelUp();
        radioRemoteController.mute();
    }

}
  • 실행 결과

장단점

  • 장점
    • 런타임 시점에 구현 클래스를 자유롭게 변경 가능하다.
      • 추상화(기능) 클래스와 구현 클래스가 분리되어 있기 때문
        • 단일 책임 원칙
    • 낮은 결합도로 유지 가능하다.
      • 추상화(기능) 클래스와 구현 클래스 각각 독립적으로 확장 가능하기 때문
        • 개방 폐쇄 원칙
    • 구현 은닉이 가능하다.
      • 클라이언트가 추상화(기능) 클래스에만 의존하기 떄문
  • 단점
    • 결합도가 높은 클래스에 패턴을 적용하면 코드가 복잡해질 수 있다.

Adapter와 Bridge 차이점

  • Adapter Pattern
    • 이미 존재하는 두 인터페이스 간의 불일치 해결
    • 인터페이스의 구현 방법 등은 고려하지 않음
    • 설계가 완료된 후 호환되지 않은 부분에 적용
  • Bridge Pattern
    • 정의와 구현을 따로 만들어서 연결
    • 새로운 구현의 추가 가능
    • 설계가 완료되기 전 추상과 개념을 각각 독립적으로 확장 가능
profile
내 맘대로 작성하는 개발일지/ 작고 소중한 개발창고

0개의 댓글