티스토리 뷰

knowledge/pattern

[Pattern] Bridge Pattern에 대하여

글을 쓰는 개발자 2021. 11. 23. 20:06
반응형

의도

구현에서 추상을 분리하여, 이들이 독립적으로 다양성을 가질 수 있도록 하는 것

활용성

추상적 개념과 이에 대한 구현 사이의 지속적인 종속 관계를 피하고 싶을 때. 이를테면, 런타임에 구현 방법을 선택하거나 구현 내요을 변경하고 싶을 때가 여기에 해당합니다.
추상적 개념과 구현 모두가 독립적으로 서브클래싱을 통해 확장되어야 할 때. 이 때, 가교 패턴은 개발자가 구현을 또 다른 추상적 개념과 연결할 수 있게 할 뿐 아니라, 각각을 독립적으로 확장 가능하게 합니다.
추상적 개념에 대한 구현 내용을 변경하는 것이 다른 관련 프로그램에 아무런 영향을 주지 않아야 할 때. 즉, 추상적 개념에 해당하는 클래스를 사용하는 코드들은 구현 클래스가 변경되었다고 해서 다시 컴파일되지 않아야 합니다.
사용자들은 사용자에게 구현을 완벽하게 은닉하길 원할 때.  가교 패턴을 사용하면 속성의 정의나 구현 메서드가 별도의 클래스에 정의되고 사용자와 개발자가 보게 되는 클래스 소스 코드에는 구현 클래스에 대한 참조자만이 정의되어 있으므로, 클래스의 구현과 속성에 대한 모든 표현 방식이 완전하게 은닉됩니다.
클래스 계통에서 클래스 수가 급증하는 것을 방지하고자 할 때. 이러한 클래스는 클래스 상속 계통에서 하나의 이유로 여러 개 클래스가 갑자기 정의되어야 하는 상황이라면 객체를 두 부분으로 분리할 필요가 있음을 보여준다.

참여자

Abstraction: 추상적 개념에 대한 인터페이스를 제공하고 객체 구현자에 대한 참조자를 관리한다.
RefinedAbstraction:  추상적 개념에 정의된 인터페이스를 확장한다.
Implementor: 구현 클래스에 대한 인터페이스를 제공. 실질적인 구현을 제공한 서브클래스들에 공통적인 연산의 시그니처만을 정의. 이 인터페이스는 Abstraction 클래스에 정의된 인터페이스에 정확하게 대응할 필요가 없다. 즉, 두 인터페이스는 서로 다른 형태일 수 있다. 일반적으로 Implementor 인터페이스는 기본적인 구현 연산을 수행하고, Abstraction은 더 추상화된 서비스 관점의 인터페이스를 제공
ConcreteImplementor: 인터페이스를 구현하는 것으로, 실제적인 구현 내용을 담았다.

 

SmartPhone.java (abstraction)

import java.util.List;

public interface SmartPhone {
    void download(App app);
    void payOn();
    void payOff();
    void allowMyPrivateInformation();
    void allowMyLocationInformation();
    void allowMyMdn();
    void allowMyAlarm();
    void disableAlarm();
    void disableMdn();
    void disablePrivateInformation();
    int getFrame();
    void play(App app);
    List<App> getApp();
}

 

iPhoneSE.java(RefinedAbstraction)

public class iPhoneSE extends SkeletonPhone implements SmartPhone{
    private static final int FRAME = 60;

    @Override
    public int getFrame() {
        return FRAME;
    }

    @Override
    public void play(App app) {
        app.play(FRAME);
    }
}

 

iPhonePro.java(RefinedAbstraction)

public class iPhonePro extends SkeletonPhone implements SmartPhone{
    private static final int FRAME = 120;

    @Override
    public int getFrame() {
        return FRAME;
    }

    @Override
    public void play(App app) {
        app.play(FRAME);
    }
}

 

 

SkeletonPhone.java

import java.util.ArrayList;
import java.util.List;

public abstract class SkeletonPhone implements SmartPhone{
    private List<App> app = new ArrayList<>();
    private boolean isPayOn = false;
    private boolean isPrivateInformationOn = false;
    private boolean isLocationInformationOn = false;
    private boolean isAlarmOn = false;
    public SkeletonPhone(){
    }
    public SkeletonPhone(List<App> app){
        this.app = app;
    }

    @Override
    public void download(App app) {
        this.app.add(app);
    }

    @Override
    public void payOn() {
        isPayOn = true;
    }

    @Override
    public void payOff() {
        isPayOn = false;
    }

    @Override
    public void allowMyPrivateInformation() {
        this.isPrivateInformationOn = true;
    }

    @Override
    public void allowMyLocationInformation() {
        this.isLocationInformationOn = true;
    }

    @Override
    public void allowMyMdn() {
        System.out.println("전화 번호 허락 성공");
    }

    @Override
    public void allowMyAlarm() {
        this.isAlarmOn = true;
    }

    @Override
    public void disableAlarm() {
        this.isAlarmOn = false;
    }

    @Override
    public void disableMdn() {
        System.out.println("전화 번호 가져오기 실패");
    }

    @Override
    public void disablePrivateInformation() {
        this.isPrivateInformationOn = false;
    }

    @Override
    public abstract int getFrame();

    @Override
    public List<App> getApp() {
        return app;
    }
}

 

 

App.java(Implementor)

public interface App {
    boolean isLocationShare();
    boolean isAllowPrivateInformation();
    boolean isAllowAlarmFunction();
    boolean isPaidApp();
    boolean isAllowMdn();
    void play(int frame);
}

 

Game.java (ConcreteImplementor)

public class Game implements App{
    private static final int FRAME = 120;
    public boolean isGraterThanRecommendedFrame(int frame){
        return FRAME<=frame;
    }

    @Override
    public String toString() {
        return "즐겁게 게임을 합시다!";
    }

    @Override
    public boolean isLocationShare() {
        return false;
    }

    @Override
    public boolean isAllowPrivateInformation() {
        return false;
    }

    @Override
    public boolean isAllowAlarmFunction() {
        return false;
    }

    @Override
    public boolean isPaidApp() {
        return false;
    }

    @Override
    public boolean isAllowMdn() {
        return false;
    }

    @Override
    public void play(int frame) {
        if (isGraterThanRecommendedFrame(frame)){
            System.out.println("시작!");
        }else{
            throw new RuntimeException("시작하실 수 없습니다.");
        }
    }
}

 

Map.java (ConcreteImplementor)

public class Map implements App{
    @Override
    public boolean isLocationShare() {
        return true;
    }

    @Override
    public boolean isAllowPrivateInformation() {
        return false;
    }

    @Override
    public boolean isAllowAlarmFunction() {
        return false;
    }

    @Override
    public boolean isPaidApp() {
        return false;
    }

    @Override
    public String toString() {
        return "지도 앱이고 기본적으로 위치공유는 true 값을 가져야 작동합니다.";
    }

    @Override
    public boolean isAllowMdn() {
        return false;
    }

    @Override
    public void play(int frame) {
        System.out.println("실행");
    }
}

 

 

 

확인 결과

    @Test
    void test(){
        iPhoneSE se = new iPhoneSE();
        iPhonePro pro = new iPhonePro();
        Game game = new Game();
        Map map = new Map();
        Sns sns = new Sns();
        assertThrows(RuntimeException.class,() -> se.play(game));
        pro.play(game);
        se.download(game);
        se.download(map);
        pro.download(game);
        pro.download(map);
        System.out.println(pro.getApp());
        System.out.println(se.getApp());
        System.out.println(pro.getFrame());
        System.out.println(se.getFrame());
    }

참고: GoF 디자인 패턴

https://refactoring.guru/design-patterns/bridge/java/example#example-0

반응형
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함