브릿지 (Bridge) 패턴
추상적인 것과 구체적인 것을 분리하여 연결하는 패턴
하나의 계층 구조일 때 보다 각기 나누었을 때 독립적인 계층 구조로 발전 시킬 수 있다.
즉, 서로 연관성이 있지만 변경될 가능성이 있는 개념들을 연결(Bridge)하여, 각각의 변경이 다른 쪽에 영향을 주지 않게함.
브릿지 패턴의 핵심(구성) 요소
Abstraction (추상화)
추상적인 개념을 표현하는 부분
클라이언트가 사용하는/ 바라보는 부분이다.
Implementor (구현체)
구체적인 기능을 구현하는 부분
보통 다른 인터페이스를 통해 구현된다.
Bridge: Abstraction과 Implementor를 연결하는 역할을 한다.
추상화 역할과 구현체 역할 모두 인터페이스로 선언하면 각각 독립적인 계층 구조로 발전이 가능하다.
이때 중요한점은 어느 한쪽의 변경이 다른 쪽에 영향을 미치지 않도록 하는 것
브릿지 (Bridge) 패턴 Before
public interface Champion {
void move();
void Q();
void W();
void E();
void R();
}
public class KDA아리 implements Champion {
@Override
public void move() {
System.out.println("KDA 아리 move");
}
@Override
public void Q() {
System.out.println("KDA 아리 Q");
}
@Override
public void W() {
System.out.println("KDA 아리 W");
}
@Override
public void E() {
System.out.println("KDA 아리 E");
}
@Override
public void R() {
System.out.println("KDA 아리 R");
}
}
public class KDA카이사 implements Champion {
@Override
public void move() {
System.out.println("KDA 카이사 move");
}
@Override
public void Q() {
System.out.println("KDA 카이사 Q");
}
@Override
public void W() {
System.out.println("KDA 카이사 W");
}
@Override
public void E() {
System.out.println("KDA 카이사 E");
}
@Override
public void R() {
System.out.println("KDA 카이사 R");
}
}
public class 수영장파티아리 implements Champion {
@Override
public void move() {
System.out.println("수영장파티 아리 move");
}
@Override
public void Q() {
System.out.println("수영장파티 아리 Q");
}
@Override
public void W() {
System.out.println("수영장파티 아리 W");
}
@Override
public void E() {
System.out.println("수영장파티 아리 E");
}
@Override
public void R() {
System.out.println("수영장파티 아리 R");
}
}
public class 수영장파티카이사 implements Champion {
@Override
public void move() {
System.out.println("수영장파티 카이사 move");
}
@Override
public void Q() {
System.out.println("수영장파티 카이사 Q");
}
@Override
public void W() {
System.out.println("수영장파티 카이사 W");
}
@Override
public void E() {
System.out.println("수영장파티 카이사 E");
}
@Override
public void R() {
System.out.println("수영장파티 카이사 R");
}
}
현재 코드는 하나의 인터페이스 Champion이 있고 해당 인터페이스를 구현하는 여러가지 구현체가 있다.
각 구현체는 스킨의 특성을 가지는데 현재 2가지가 존재한다. (KDA / 수영장파티)
이때 새로운 "정복자아리" 스킨+챔피언을 만든다고 하면?
public class 정복자아리 implements Champion {
@Override
public void move() {
System.out.println("정복자 아리 move");
}
@Override
public void Q() {
System.out.println("정복자 아리 Q");
}
@Override
public void W() {
System.out.println("정복자 아리 W");
}
@Override
public void E() {
System.out.println("정복자 아리 E");
}
@Override
public void R() {
System.out.println("정복자 아리 R");
}
}
중복 코드가 많고 만약 스킨 이름을 정복자가 아닌 다른 이름으로 바꾸게 되면
모든 메소드에 수정이 들어간다.
이를 브릿지 패턴을 적용해서 각각 챔피언 자체와 스킨으로 분리하여
각각의 확장을 편이하게 해보겠다.
브릿지 (Bridge) 패턴 After
public interface Champion {
void move();
void Q();
void W();
void E();
void R();
}
public interface Skin {
String getName();
}
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 Q() {
System.out.printf("%s %s Q\n", skin.getName(), this.name);
}
@Override
public void W() {
System.out.printf("%s %s W\n", skin.getName(), this.name);
}
@Override
public void E() {
System.out.printf("%s %s E\n", skin.getName(), this.name);
}
@Override
public void R() {
System.out.printf("%s %s R\n", skin.getName(), this.name);
}
}
public class 아리 extends DefaultChampion{
public 아리(Skin skin) {
super(skin, "아리");
}
}
public class KDA implements Skin {
@Override
public String getName() {
return "KDA";
}
}
// 다른 구현체들 생략 ..
해당 구조에서 똑같이 정복자 아리를 추가한다고 하면?
스킨만 추가하면 끝이다.
public class 정복자 implements Skin {
@Override
public String getName() {
return "정복자";
}
}
해당 구조에서 챔피언(야스오)을 추가하면?
public class 야스오 extends DefaultChampion{
public 야스오(Skin skin) {
super(skin, "야스오");
}
}
정리
새로운 스킨이나 챔피언을 추가할 때 기존 코드를 거의 수정할 필요가 없고, 클라이언트 코드에서도 새로운 인스턴스를 손쉽게 생성할 수 있다.
스킨과 챔피언을 독립적으로 추가 및 변경할 수 있어 유연한 확장이 가능
새로운 기능을 추가할 때 기존 코드에 미치는 영향이 적다.
공통된 동작을 DefaultChampion 클래스에서 관리하므로 코드 중복이 줄어든다.
브릿지 (Bridge) 패턴 정리
브릿지 패턴: 추상적인 것과 구체적인 것을 분리하여 연결하는 패턴
장점
추상적인 코드를 구체적인 코드 변경 없이도 독립적으로 확장할 수 있다.
→ OCP
추상적인 코드와 구체적인 코드를 분리할 수 있다.
→ SRP
단점
계층 구조가 늘어나서 복잡도가 증가할 수 있다.
브릿지 (Bridge) 패턴 적용 사례
JDBC에서의 브릿지 패턴 분석
JDBC 복습
JDBC 드라이버는 Java 애플리케이션과 데이터베이스 간의 연결을 처리하는 컴포넌트
데이터베이스와의 통신을 가능하게 하며, JDBC API를 통해 SQL 쿼리를 실행하고 결과를 반환
예: MySQL 드라이버, Oracle 드라이버 등
DriverManager JDBC 드라이버 관리 클래스
애플리케이션이 데이터베이스에 연결할 때 드라이버를 로드하고, 등록된 드라이버 중에서 적절한 드라이버를 선택하여 연결을 생성
드라이버 등록: DriverManager.registerDriver()
데이터베이스 연결: DriverManager.getConnection(url, user, password)
각 Driver 3개의 인터페이스를 구현
Connection
Statement
ResultSet
public class JdbcExample {
public static void main(String[] args) throws ClassNotFoundException{
Class.forName("org.h2.Driver");
try(Connection conn = DriverManager.getConnection("jdbc:h2:mem:~/test", "sa", "")){
String sql = "";
Statement statement = conn.createStatement();
statement.execute(sql);
}
catch (SQLException e){
throw new RuntimeException(e);
}
}
}
추상화(Abstraction)
Driver가 추상화 역할을 한다.
데이터베이스와 상호작용하는 고수준의 인터페이스를 정의한다.
구현자(Implementor)
Connection, Statement, ResultSet 인터페이스가 구현자 역할을 수행한다.
이 인터페이스들은 데이터베이스와 상호작용하는 핵심 기능들을 제공하지만, 이 기능들이 어떻게 실행되는지
어떤 데이터베이스와 상호작용하는지는 명시하지 않는다.
구체적인 구현자 (Concrete Implementor)
각 데이터베이스 드라이버(H2, MySQL ...)는 이러한 인터페이스를 구현한다.
ex) org.h2.Driver는 Driver 인터페이스를 구현하여 연결을 생성하고, 쿼리를 실행하며, 결과를 반환하는 구체적인 로직을 제공한다.
OCP 측면
새로운 데이터베이스에 맞게 DriverManager를 구현할 수 있다.
또한 DriverManger 클래스는 전혀 변경하지 않고도 새로운 데이터베이스 드라이버를 추가하거나 이존 드라이버를 수정할 수 있다.
즉, 각 계층 구조가 서로 독립적이다.
Spring TransactionManager 브릿지 패턴 분석
TransactionTemplate - 추상화(Abstraction)
TransactionManager - 구현자(Implementor)
(Platform)TransactionManager의 여러 구현체 - 구체적인 구현자 (Concrete Implementor)
public class TransactionTemplate extends DefaultTransactionDefinition
implements TransactionOperations, InitializingBean {
@Nullable
private PlatformTransactionManager transactionManager;
// ... 생략
}
'Computer Sience > Desgin Pattern' 카테고리의 다른 글
[Design Pattern] 데코레이터 (Decorator) 패턴 (0) | 2024.10.28 |
---|---|
[Design Pattern] 컴포짓 (Composite) 패턴 (1) | 2024.10.24 |
[Design Pattern] 어댑터 (Adapter) 패턴 (2) | 2024.10.22 |
[Design Pattern] 프로토타입 (Prototype) 패턴 (2) | 2024.10.20 |
[Design Pattern] 빌더(Builder) 패턴 (6) | 2024.10.19 |