본문 바로가기
Develop/Fundmental

Bridge Pattern(브릿지 패턴)

by 3-stack 2022. 5. 1.

브리지 패턴(Bridge pattern)

구현(implementation)부에서 추상(abstraction)레이어를 분리하여 각자 독립적으로 변형할 수 있게 하는 패턴이다.

기능과 구현에 대해서 두 개를 별도의 클래스로 구현한다.

두 개의 다른 계층(하나는 추상, 하나는 구현인 서로 다른 계층의 커플링을 약화시키며 협력은 가능하도록 하는 패턴)

 

Abstraction

기능 계층의 최상위 클래스이며 추상 인터페이스를 정의한다. Implementor에 대한 레퍼런스를 유지한다.

구현 부분에 해당하는 클래스를 인터페에스를  가지고 해당 인스턴스를 통해 구현 부분의 메서드를 호출한다.

RefinedAbstraction

Abstraction에 의해 정의한 인터페이스를 확장한다.(extends)

기능 계층에서 새로운 부분을 확장한 클래스.

Implementor

구현 클래스를 위한 인터페이스를 정의한다.

Abstraction의 기능을 구현하기 위한 인터페이스를 정의한다.

ConcreteImplementor

Implementor 인터페이스를 구현. 즉, 실제 기능을 구현한다.

 

 

코드 예제를 통해 알아보자.

움직이고 공격하는 기능의 챔피언 인터페이스가 있고, 챔피언은 가렌, 다리우스 등등 다양하게 만들어질 수 있다.

챔피언들은 스킨으로 다양하게 구현될 수 있다.

 

◎ 챔피언 인터페이스

- 때리고 움직인다.

public interface Champion {
  public void attack();
  public void move();
}

가렌 클래스 구현

public class Garen implements Champion {
  String name;

  public Garen() {
    this.name = "garen";
  }

  @Override
  public void attack() {
    System.out.printf("%s ATTACK!!! \n", this.name);
  }

  @Override
  public void move() {
    System.out.printf("%s MOVE!!! \n", this.name);
  }
}

 신성왕 가렌

- 신성왕 스킨과 가렌의 속성이 섞여 있다.

public class HolyKingGaren extends Garen {
  public HolyKingGaren() {
  }

  @Override
  public void attack() {
    System.out.printf("HolyKing %s ATTACK!!! \n", this.name);
  }

  @Override
  public void move() {
    System.out.printf("HolyKing %s MOVE!!! \n", this.name);
  }
}

◎ 핏빛 가렌

- 핏빛 스킨과 가렌의 속성이 섞여 있다.

public class BloodyGaren extends Garen {
  public BloodyGaren() {
  }

  @Override
  public void attack() {
    System.out.printf("Bloody %s ATTACK!!! \n", this.name);
  }

  @Override
  public void move() {
    System.out.printf("Bloody %s MOVE!!! \n", this.name);
  }
}

 사용

public class Client {
  public static void main(String[] args) {
    Garen bloodyGaren = new BloodyGaren();
    bloodyGaren.attack();
    bloodyGaren.move();
    Garen holyKingGarenaren = new HolyKingGaren();
    holyKingGarenaren.attack();
    holyKingGarenaren.move();
  }
}

 

스킨에 따라 구체적인 구현부(HolyKing, Bloody)가 달라지기 때문에

* 가렌의 attack, move 메서드도 수정이 필요해진다.

* 스킨 구현체와 가렌 상품의 기능이 같이 커플링 되어있어 중복 코드가 발생한다.

스킨을 분리하자!!!

 

 스킨 인터페이스

public interface Skin {
  public String getName();
}

 신성왕 스킨 구현

public class HolyKingSkin implements Skin {
  @Override
  public String getName() {
    return "HolyKing";
  }
}

 핏빛 스킨 구현

public class BloodySkin implements Skin {
  @Override
  public String getName() {
    return "Bloody";
  }
}

사용

- 기존에 사용하던 스킨과 가렌이 섞여있던 HolyKingGaren을 사용하지 않고, 가렌과 스킨을 분리해서 구현했다.

public class Client {
  public static void main(String[] args) {
    Garen bloodyGaren = new Garen(new BloodySkin());
    bloodyGaren.attack();
    bloodyGaren.move();
    Garen holyKingGarenaren = new Garen(new HolyKingSkin());
    holyKingGarenaren.attack();
    holyKingGarenaren.move();
  }
}

 

장점

추상적인 코드를 구체적인 코드 변경 없이도 독립적으로 확장할 수 있다.

추상적인 코드과 구체적인 코드를 분리하여 수 있다.

단점

계층 구조가 늘어나 복잡도가 증가할 수 있다.

 

 

 

 

댓글