Programing

브리지 패턴은 언제 사용합니까?

lottogame 2020. 6. 13. 10:12
반응형

브리지 패턴은 언제 사용합니까? 어댑터 패턴과 어떻게 다릅니 까?


실제 응용 프로그램에서 브리지 패턴사용한 사람이 있습니까? 그렇다면 어떻게 사용 했습니까? 나입니까, 아니면 믹스에 약간의 의존성 주입이있는 어댑터 패턴입니까? 실제로 자체 패턴이 필요합니까?


브리지 패턴의 고전적인 예는 UI 환경에서 도형 정의에 사용됩니다 ( 브리지 패턴 위키 백과 항목 참조 ). 브리지 패턴은 템플릿전략 패턴 합성 입니다 .

브릿지 패턴에서 어댑터 패턴의 일부 측면을 공통적으로 볼 수 있습니다. 그러나이 기사 에서 인용 하면 :

언뜻보기에 브리지 패턴은 클래스가 한 종류의 인터페이스를 다른 인터페이스로 변환하는 데 사용된다는 점에서 어댑터 패턴과 매우 유사합니다. 그러나 Adapter 패턴의 의도는 하나 이상의 클래스 인터페이스가 특정 클래스의 인터페이스와 동일하게 보이도록하는 것입니다. Bridge 패턴은 클래스의 인터페이스를 구현에서 분리하도록 설계되어 있으므로 클라이언트 코드를 변경하지 않고도 구현을 변경하거나 대체 할 수 있습니다.


FedericoJohn의 대답 이 조합되어 있습니다.

언제:

                   ----Shape---
                  /            \
         Rectangle              Circle
        /         \            /      \
BlueRectangle  RedRectangle BlueCircle RedCircle

리팩터링 :

          ----Shape---                        Color
         /            \                       /   \
Rectangle(Color)   Circle(Color)           Blue   Red

Bridge 패턴은 "상속보다 컴포지션 선호"라는 오래된 조언을 적용한 것입니다. 서로 직교하는 방식으로 다른 시간을 서브 클래 싱해야 할 때 편리합니다. 컬러 모양의 계층 구조를 구현해야한다고 가정 해보십시오. Rectangle 및 Circle을 사용하여 Shape를 서브 클래스 화 한 다음 RedRectangle, BlueRectangle 및 GreenRectangle을 사용하여 Rectangle을 서브 클래스 화하고 Circle과 동일하게 서브 클래스를 작성 하시겠습니까? 각 셰이프 에는 색상 있고 색상의 계층 구조를 구현하는 것이 좋습니다. 이것이 브리지 패턴입니다. 글쎄, 나는 "색상 계층"을 구현하지는 않지만 아이디어를 얻는다.


언제:

        A
     /     \
    Aa      Ab
   / \     /  \
 Aa1 Aa2  Ab1 Ab2

리팩터링 :

     A         N
  /     \     / \
Aa(N) Ab(N)  1   2

어댑터와 브리지는 확실히 관련이 있으며 구별은 미묘합니다. 이러한 패턴 중 하나를 사용한다고 생각하는 일부 사람들은 실제로 다른 패턴을 사용하고있을 가능성이 있습니다.

내가 본 설명은 이미 존재 하는 호환되지 않는 클래스의 인터페이스를 통합하려고 할 때 Adapter가 사용된다는 것 입니다. 어댑터는 레거시 로 간주 될 수있는 구현에 대한 일종의 번역기 역할을합니다 .

브리지 패턴은 그린 필드 일 가능성이 높은 코드에 사용됩니다. 다양한 구현이 필요한 추상 인터페이스를 제공하기 위해 Bridge를 설계하고 있지만 해당 구현 클래스의 인터페이스도 정의합니다.

장치 드라이버는 Bridge에서 자주 인용되는 예이지만 장치 공급 업체의 인터페이스 사양을 정의하는 경우에는 Bridge라고 말하지만 기존 장치 드라이버를 가져 와서 랩퍼 클래스를 만드는 경우에는 어댑터라고합니다. 통합 인터페이스를 제공합니다.

따라서 코드 측면에서 두 패턴은 매우 유사합니다. 비즈니스 측면에서는 서로 다릅니다.

http://c2.com/cgi/wiki?BridgePattern 도 참조 하십시오


내 경험에 따르면 Bridge는 도메인에 두 개의 직교 치수가 있을 때마다 솔루션이기 때문에 매우 자주 반복되는 패턴 입니다. 예를 들어 모양 및 그리기 방법, 동작 및 플랫폼, 파일 형식 및 시리얼 라이저 등.

그리고 충고 : 항상 디자인 관점을 구현 관점이 아니라 개념 관점에서 생각 하십시오. 올바른 관점에서 Bridge는 다른 문제를 해결하기 때문에 어댑터와 혼동 될 수 없으며 구성은 자체를 위해서가 아니라 직교 문제를 개별적으로 처리 할 수 ​​있기 때문에 상속보다 우수합니다.


BridgeAdapter 의 의도 가 다르므로 두 패턴을 별도로 필요로합니다.

다리 패턴 :

  1. 구조적인 패턴입니다
  2. 컴파일 타임에 추상화 및 구현이 바인딩되지 않습니다
  3. 추상화 및 구현 – 둘 다 클라이언트에 영향을주지 않으면 서 다를 수 있습니다
  4. 상속보다 구성을 사용합니다.

다음과 같은 경우 브리지 패턴을 사용하십시오.

  1. 구현의 런타임 바인딩을 원합니다.
  2. 결합 된 인터페이스와 수많은 구현으로 인해 클래스가 급증합니다.
  3. 여러 객체간에 구현을 공유하려고합니다.
  4. 직교 클래스 계층 구조를 매핑해야합니다.

@ John Sonmez 답변은 클래스 계층 구조를 줄이는 데 브리지 패턴의 효과를 명확하게 보여줍니다.

코드 예제를 사용하여 브리지 패턴에 대한 더 나은 통찰력을 얻으려면 아래 문서 링크를 참조하십시오

어댑터 패턴 :

  1. 작업 함께 두 관련이없는 인터페이스를 허용 가능한 같은 역할을하고, 다른 객체를 통해.
  2. 원래 인터페이스를 수정합니다.

주요 차이점 :

  1. 어댑터 는 디자인 된 후에 작동합니다. Bridge 는 이전에 작동하도록합니다.
  2. Bridge추상화와 구현이 독립적으로 변할 수 있도록 사전에 설계되었습니다 . 어댑터 는 관련없는 클래스가 함께 작동하도록 개조되었습니다.
  3. 의도 : 어댑터를 사용하면 두 개의 관련되지 않은 인터페이스를 함께 사용할 수 있습니다. Bridge를 사용하면 추상화와 구현이 독립적으로 달라질 수 있습니다.

UML 다이어그램 및 작업 코드 관련 SE 질문 :

브리지 패턴과 어댑터 패턴의 차이점

유용한 기사 :

소스 메이킹 브릿지 패턴 기사

소스 제작 어댑터 패턴 기사

journaldev 브리지 패턴 기사

편집하다:

브리지 패턴 실제 예제 (meta.stackoverflow.com 제안에 따라 문서가해질 예정이므로이 게시물에 통합 된 문서 사이트 예제)

브리지 패턴은 구현과 추상화를 분리하여 둘 다 독립적으로 변할 수 있습니다. 상속보다는 구성으로 달성되었습니다.

Wikipedia의 브릿지 패턴 UML :

Wikipedia의 브릿지 패턴 UML

이 패턴에는 네 가지 구성 요소가 있습니다.

Abstraction: 인터페이스를 정의합니다

RefinedAbstraction: 추상화를 구현합니다.

Implementor: 구현을위한 인터페이스를 정의합니다

ConcreteImplementor: Implementor 인터페이스를 구현합니다.

The crux of Bridge pattern :컴포지션을 사용하고 상속하지 않는 두 개의 직교 클래스 계층 구조 추상화 계층과 구현 계층은 독립적으로 다를 수 있습니다. 구현은 추상화를 참조하지 않습니다. 추상화에는 컴포지션을 통해 멤버로 구현 인터페이스가 포함되어 있습니다. 이 구성은 하나 이상의 수준의 상속 계층을 줄입니다.

실제 사용 사례 :

다른 차량에 수동 및 자동 기어 시스템 버전을 모두 사용할 수 있습니다.

예제 코드 :

/* Implementor interface*/
interface Gear{
    void handleGear();
}

/* Concrete Implementor - 1 */
class ManualGear implements Gear{
    public void handleGear(){
        System.out.println("Manual gear");
    }
}
/* Concrete Implementor - 2 */
class AutoGear implements Gear{
    public void handleGear(){
        System.out.println("Auto gear");
    }
}
/* Abstraction (abstract class) */
abstract class Vehicle {
    Gear gear;
    public Vehicle(Gear gear){
        this.gear = gear;
    }
    abstract void addGear();
}
/* RefinedAbstraction - 1*/
class Car extends Vehicle{
    public Car(Gear gear){
        super(gear);
        // initialize various other Car components to make the car
    }
    public void addGear(){
        System.out.print("Car handles ");
        gear.handleGear();
    }
}
/* RefinedAbstraction - 2 */
class Truck extends Vehicle{
    public Truck(Gear gear){
        super(gear);
        // initialize various other Truck components to make the car
    }
    public void addGear(){
        System.out.print("Truck handles " );
        gear.handleGear();
    }
}
/* Client program */
public class BridgeDemo {    
    public static void main(String args[]){
        Gear gear = new ManualGear();
        Vehicle vehicle = new Car(gear);
        vehicle.addGear();

        gear = new AutoGear();
        vehicle = new Car(gear);
        vehicle.addGear();

        gear = new ManualGear();
        vehicle = new Truck(gear);
        vehicle.addGear();

        gear = new AutoGear();
        vehicle = new Truck(gear);
        vehicle.addGear();
    }
}

산출:

Car handles Manual gear
Car handles Auto gear
Truck handles Manual gear
Truck handles Auto gear

설명:

  1. Vehicle 추상화입니다.
  2. CarTruck두 가지 구체적인 구현입니다 Vehicle.
  3. Vehicle추상 메소드를 정의합니다 addGear().
  4. Gear 구현 자 인터페이스
  5. ManualGear그리고 AutoGear두 가지 구현입니다Gear
  6. Vehicleimplementor인터페이스를 구현하는 대신 인터페이스를 포함 합니다. Compositon구현 자 인터페이스는이 패턴의 요점입니다. 추상화와 구현은 독립적으로 변할 수 있습니다.
  7. Car그리고 Truck추상화를위한 구현 (재정의 된 추상화)을 정의합니다 : addGear(): 포함 Gear- Manual또는Auto

브리지 패턴의 사용 사례 :

  1. 추상화구현 은 서로 독립적으로 변경 될 수 있으며 컴파일 타임에 바인딩되지 않습니다.
  2. 직교 계층 구조를 매핑하십시오. 하나는 추상화를 위한 것이고 다른 하나는 구현위한 것 입니다.

직장에서 다리 패턴을 사용했습니다. 나는 C ++로 프로그램하는데, 종종 PIMPL 관용구 (구현 포인터)라고 불린다. 다음과 같이 보입니다 :

class A
{
public: 
  void foo()
  {
    pImpl->foo();
  }
private:
  Aimpl *pImpl;
};

class Aimpl
{
public:
  void foo();
  void bar();
};  

이 예제 class A에는 인터페이스와 class Aimpl구현이 포함되어 있습니다.

이 패턴의 한 가지 용도는 구현 클래스의 일부 공용 멤버 만 노출하고 다른 클래스는 노출하지 않는 것입니다. 이 예에서는의 Aimpl::foo()공용 인터페이스를 통해서만 호출 할 수 A있지만Aimpl::bar()

다른 장점은 Aimpl의 사용자가 포함 할 필요가없는 별도의 헤더 파일로 정의 할 수 있다는 것 입니다 A. Aimplbefore 의 forward 선언 A이 정의되어 있고 참조하는 모든 멤버 함수의 정의를 pImpl.cpp 파일로 이동하기 만하면됩니다. 이를 통해 Aimpl헤더를 비공개 로 유지 하고 컴파일 시간을 줄일 수 있습니다.


코드에 모양 예제를 넣으려면 :

#include<iostream>
#include<string>
#include<cstdlib>

using namespace std;

class IColor
{
public:
    virtual string Color() = 0;
};

class RedColor: public IColor
{
public:
    string Color()
    {
        return "of Red Color";
    }
};

class BlueColor: public IColor
{
public:
    string Color()
    {
        return "of Blue Color";
    }
};


class IShape
{
public:
virtual string Draw() = 0;
};

class Circle: public IShape
{
        IColor* impl;
    public:
        Circle(IColor *obj):impl(obj){}
        string Draw()
        {
            return "Drawn a Circle "+ impl->Color();
        }
};

class Square: public IShape
{
        IColor* impl;
    public:
        Square(IColor *obj):impl(obj){}
        string Draw()
        {
        return "Drawn a Square "+ impl->Color();;
        }
};

int main()
{
IColor* red = new RedColor();
IColor* blue = new BlueColor();

IShape* sq = new Square(red);
IShape* cr = new Circle(blue);

cout<<"\n"<<sq->Draw();
cout<<"\n"<<cr->Draw();

delete red;
delete blue;
return 1;
}

출력은 다음과 같습니다.

Drawn a Square of Red Color
Drawn a Circle of Blue Color

순열로 인한 서브 클래스 폭발없이 새로운 색상과 모양을 시스템에 쉽게 추가 할 수 있습니다.


나를 위해 인터페이스를 교환 할 수있는 메커니즘으로 생각합니다. 실제로는 하나 이상의 인터페이스를 사용할 수있는 클래스 인 Bridge를 통해 교환 할 수 있습니다.


Bridge design pattern we can easily understand helping of service and dao layer.

Dao layer -> create common interface for dao layer ->
public interface Dao<T>{
void save(T t);
}
public class AccountDao<Account> implement Dao<Account>{
public void save(Account){
}
}
public LoginDao<Login> implement Dao<Login>{
public void save(Login){
}
}
Service Layer ->
1) interface
public interface BasicService<T>{
    void save(T t);
}
concrete  implementation of service -
Account service -
public class AccountService<Account> implement BasicService<Account>{
 private Dao<Account> accountDao;
 public AccountService(AccountDao dao){
   this.accountDao=dao;
   }
public void save(Account){
   accountDao.save(Account);
 }
}
login service- 
public class LoginService<Login> implement BasicService<Login>{
 private Dao<Login> loginDao;
 public AccountService(LoginDao dao){
   this.loginDao=dao;
   }
public void save(Login){
   loginDao.save(login);
 }
}

public class BridgePattenDemo{
public static void main(String[] str){
BasicService<Account> aService=new AccountService(new AccountDao<Account>());
Account ac=new Account();
aService.save(ac);
}
}
}

참고 : https://stackoverflow.com/questions/319728/when-do-you-use-the-bridge-pattern-how-is-it-different-from-adapter-pattern

반응형