반응형
Notice
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 소프트웨어
- 인공지능
- 빅데이터
- 프로그래밍언어
- 자바스크립트
- 사이버보안
- 네트워크
- 딥러닝
- 알고리즘
- 클라우드컴퓨팅
- 프로그래밍
- 데이터베이스
- 컴퓨터비전
- 디자인패턴
- I'm Sorry
- 버전관리
- 자료구조
- 컴퓨터공학
- 머신러닝
- 네트워크보안
- 컴퓨터과학
- 파이썬
- 데이터분석
- 웹개발
- 데이터과학
- 데이터구조
- 소프트웨어공학
- Yes
- springboot
- 보안
Archives
- Today
- Total
스택큐힙리스트
Bridge 패턴: 기능·구현을 갈라놓는 비밀 통로 본문
반응형
“화면 UI·비즈니스 로직은 계속 늘어나는데, 코드 변경할 때마다 여기저기 연쇄 폭탄이 터진다…”
프런트엔드 React와 백엔드 Spring Boot를 병행 개발하다 보면 자주 듣는 한숨입니다. Bridge 패턴은 이런 의존성 폭발을 막아 주는 구조(Structural) 패턴. 추상화(기능)와 구현을 ‘다리(Bridge)’로 연결해 둘을 완전히 독립시켜 주죠.
1️⃣ Bridge 패턴이 뭔가요?
- 정의: 추상 인터페이스(Abstraction)와 실제 구현체(Implementor)를 별도 계층 으로 분리, 런타임에 조합하도록 해 주는 구조 패턴.
- 효과: 기능·구현 계층을 따로 확장하므로 “새 기능 추가 ↔ 기존 구현 교체”를 마음껏 조합할 수 있습니다.
- 자주 쓰는 상황
- 플랫폼별(웹·모바일) UI 레이어가 같지만 렌더링 엔진이 다를 때
- 결제·로그 수집 등 벤더 교체 가능성을 열어 두고 싶을 때
- 복잡한 상속 트리 때문에 클래스 폭발이 일어날 때
2️⃣ React 예시 – 뷰 라이브러리 교체에도 끄떡없는 버튼 컴포넌트
// Implementor 역할 – 실제 렌더링 전략
export interface ButtonRenderer {
render(label: string, onClick: () => void): JSX.Element;
}
export class MaterialUIButton implements ButtonRenderer {
render(label, onClick) {
return <MuiButton onClick={onClick}>{label}</MuiButton>;
}
}
export class TailwindButton implements ButtonRenderer {
render(label, onClick) {
return (
<button
className="rounded-xl px-4 py-2 bg-indigo-500 text-white"
onClick={onClick}
>
{label}
</button>
);
}
}
// Abstraction 역할 – ‘기능’만 정의
export class BridgeButton {
constructor(private renderer: ButtonRenderer) {}
draw(label: string, action: () => void) {
return this.renderer.render(label, action);
}
}
// 사용 – 런타임에 조합!
const SaveButton = new BridgeButton(new MaterialUIButton());
// 또는 프리미엄 테마
// const SaveButton = new BridgeButton(new TailwindButton());
버튼 기능은 그대로 두고, 외관 구현만 바꿔 꼽으면 끝. 덕분에 디자인 시스템 변경에도 컴포넌트 로직은 단 한 줄도 손대지 않습니다.
3️⃣ Spring Boot 예시 – DB 벤더 교체를 위한 Repository Bridge
// Implementor – DB 연동 전략
public interface AccountStore {
AccountEntity findById(String id);
void save(AccountEntity entity);
}
@Repository
@RequiredArgsConstructor
public class MySQLAccountStore implements AccountStore {
private final JdbcTemplate jdbc;
// ...구체 SQL 구현
}
@Repository
@RequiredArgsConstructor
public class MongoAccountStore implements AccountStore {
private final MongoTemplate mongo;
// ...Mongo 쿼리 구현
}
// Abstraction – 도메인 서비스
@Service
@RequiredArgsConstructor
public class AccountService {
private final AccountStore store; // 다리를 건넌다!
public Account find(String id) {
return Account.from(store.findById(id));
}
}
JPA → MongoDB 로 갈아타야 할 때? AccountStore 구현체만 주입 교체하면 도메인 로직은 그대로 보존됩니다.
4️⃣ 구현 꿀팁 •🔥
- 조합(Composition) 우선: 다형성을 위한 상속 대신 인터페이스 + 의존성 주입을 쓰면 테스트 대역(Mock) 작성이 편리합니다.
- 런타임 스위칭: 스프링에서는 @Profile, React에서는 DI 컨테이너·Context를 이용해 구현체를 조건부로 주입하세요.
- Adapter·Facade와 함께: 외부 API 형태가 들쑥날쑥하다면 Adapter로 맞춘 뒤 Bridge로 조합하면 더 깔끔합니다.
- 네이밍 규칙: *Renderer, *Store, *Gateway 처럼 Implementor를 한눈에 구분되는 접미사로 통일하면 유지보수성이 올라갑니다.
5️⃣ 장·단점 요약
- 👍 확장성: 기능/구현 각각 선형적으로 늘어날 수 있어 클래스 폭발을 막습니다.
- 👍 리팩터링 유연성: 구현 기술 교체(예: MySQL → Mongo) 시 비즈니스 코드 무변경.
- ⚠️ 설계 난이도: 초기 구조를 잘못 잡으면 ‘다리 위의 다리’처럼 과도한 추상화가 될 수 있으니, 변경 가능성이 높은 축에만 적용하세요.
한 줄 요약
Bridge 패턴은 “변화할 축을 물 위·물 아래로 갈라 놓고, 다리만 건너는” 전략입니다. 기능과 구현을 떼어내면, 당신의 코드베이스는 언제든 새 길을 놓을 준비가 돼요.
반응형
'개발' 카테고리의 다른 글
데코레이터 패턴: 핵심 기능에 ‘슈퍼파워’를 덧입히는 법 (0) | 2025.07.18 |
---|---|
Composite 패턴으로 백엔드 트리 구조 깔끔하게 다루기 (2) | 2025.07.18 |
Adapter 패턴으로 레거시 API 호환하기 (1) | 2025.07.17 |
레거시 API도 걱정 끝! 리액트·스프링에서 Adapter·Facade 패턴으로 우아하게 래핑하기 (0) | 2025.07.17 |
Actuator로 헬스 체크 실시간 모니터링 (1) | 2025.07.17 |
Comments