

브릿지 패턴 정리
DesignPattern
2025.11.04.
1. 브릿지 패턴
- 추상적인 것과 구체적인 것을 분리하여 연결하는 패턴
- 브릿지 패턴의 핵심은 “기능 클래스 계층” 과 “구현 클래스 계층” 의 분리
- 기능 클래스 : 기본 기능을 가지고 있는 부모 클래스를 상속 받아 새로운 기능이 추가된 하위 클래스
- 구현 클래스 : 기능을 정의한 추상 클래스(or 인터페이스)의 기능을 구현한 하위 클래스
- 클래스 계층이 하나여서 기능과 구현이 함께 있으면, 새로운 기능이 추가될 수록 무거워짐
- 이로 인해 한개의 클래스 권한이 너무 커지고 의존하는 형태
- 2가지 계층을 분리해서 관리하고 2계층을 연결하기 위한 패턴이
브릿지 패턴
2. 브릿지 패턴 구조 및 특징
- 클라이언트는 구현체를 직접 사용하지 않고 추상적인 인터페이스를 사용
- 하나의 계층 구조일 때 보다 2개의 계층구조(기능, 구현)로 나누었을 때 독립적인 계층 구조로 발전 가능
상속
- 상속은 상위 클래스에 공통 로직을 구현해두고, 자식 클래스에서 이를 재사용하는 방법
- 흔히 Is-a 관계라고 불림
public class Person {
public void walk() {
System.out.println("걷다");
}
public void talk() {
System.out.println("말한다.");
}
}
public class Chef extends Person {
}
합성
- 합성은 중복되는 로직들을 가지는 객체를 구현하고, 이를 주입받아 호출해서 재사용하는 방법
- 상속과 유사하지만, 한 클래스가 다른 클래스의 객체를 포함하는 관계이기 때문에 Has-a 관계라고 불림
public class Chef {
private Person person;
private List<Food> foodList;
public Chef(Person person, List<Food> foodList) {
this.person = person;
this.foodList = foodList;
}
public int calculatePrice() {
return foodList.stream()
.mapToInt(v -> v.getPrice())
.sum();
}
}
public class Person {
public void walk() {
System.out.println("걷는다");
}
public void talk() {
System.out.println("말한다");
}
}
3. 브릿지 패턴 구현
- 공통 기능(행동)을 정의해둔 인터페이스 정의
public interface Champion {
void move();
void skillQ();
void skillW();
void skillE();
void skillR();
}
public interface Skin {
String getName();
}
//Skin 구현체들
public class PoolParty_skin implements Skin{
@Override
public String getName() {
return "PoolParty Skin";
}
}
public class KDA_skin implements Skin{
@Override
public String getName() {
return "KDA Skin";
}
}
- 구현 클래스 구현
- DefaultChampion은 Champion의 기능을 구현한 1개의 구현 클래스 계층
- DefaultChampion은 Skin을 외부에서 주입받아 멤버 변수로 가지고 있다.
- Skin은 기능을 정의만 한 인터페이스 이므로, 외부에서 Skin을 구현한 또 다른 구현 계층 클래스를 주입받아야 한다.
- 외부에서 주입받는 Skin필드가 두 클래스 계층을 연결하는 **다리(Bridge)**가 된다.
public class DefaultChampion implements Champion {
private Skin skin;
private String name;
public DefaultChampion(Skin skin, String name) {
this.skin = skin;
this.name = name;
}
@Override
public void move() {
System.out.printf("%s %s move\n", skin.getName(), this.name);
}
@Override
public void skillQ() {
System.out.printf("%s %s Q skill \n", skin.getName(), this.name);
}
@Override
public void skillW() {
System.out.printf("%s %s W skill \n", skin.getName(), this.name);
}
@Override
public void skillE() {
System.out.printf("%s %s E skill \n", skin.getName(), this.name);
}
@Override
public void skillR() {
System.out.printf("%s %s R skill \n", skin.getName(), this.name);
}
}
- 클라이언트 코드
- 브릿지 패턴으로 계층구조를 분리한 후 연결하니, 서로 다른 계층 구조에서 추가적인 요구사항에 따라 확장이 가능해짐
- 클라이언트에서 사용할 계층 구조를 주입하여 2계층 구조를 연결해주는 구조가 완성
public class App {
public static void main(String[] args) {
Champion kda아리 = new 아리(new KDA_skin());
kda아리.move();
kda아리.skillQ();
Champion poolParty아리 = new 아리(new PoolParty_skin());
poolParty아리.move();
poolParty아리.skillR();
}
}
public class 아리 extends DefaultChampion {
public 아리(Skin skin) {
super(skin, "아리");
}
}
public class 아칼리 extends DefaultChampion {
public 아칼리(Skin skin) {
super(skin, "아칼리");
}
}
4. 브릿지 패턴을 적용하지 않으면
- 계층 구조가 무거워짐에 따라 중복 코드가 늘고, 모든 기능을 한 객체에서 관리하기에 의존도도 높아진다.
- 각기 다른 세부적인 특징들이 달라질수록 그에 따른 구현체들도 기하 급수적으로 늘어나게 된다.
5. 브릿지 패턴 장점 및 단점
장점
- 추상적인 코드를 구체적인 코드 변경 없이도 독립적으로 확장 가능
- 추상적인 코드와 구체적인 코드를 분리할 수 있다.
단점
- 계층 구조가 늘어나 복잡도가 증가할 수 있다.