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


125

브리지와 어댑터 패턴의 차이점은 무엇입니까?


둘 중 하나를 사용해야한다고 생각하는 위치에 대한 토론을 안내하기 위해 설명 편집을 제공하는 것이 좋습니다.
Jeff Wilcox


답변:


173

"Adapter는 설계 후에 작동하게하고 Bridge는 작동하기 전에 작동하도록합니다. [GoF, p219]"

효과적으로 어댑터 패턴은 기존 코드 (타사 또는 사내)가 있지만 제어 할 수 없거나 필요한 인터페이스를 충족하기 위해 변경할 수없는 경우에 유용합니다. 예를 들어, 우리는 파멸의 날 장치의 미세한 배열을 제어 할 수있는 SuperWeaponsArray를 가지고 있습니다.

public class SuperWeaponsArray {
  /*...*/

  public void destroyWorld() {
    for (Weapon w : armedWeapons) {
      w.fire();
    }
  }
}

큰. 무기 인터페이스로의 전환보다 훨씬 앞선 핵 장치가 무기고에 있다는 사실을 깨닫는 것 외에는 말입니다. 하지만 우리는 그것이 여기서 작동하기를 정말로 원합니다. 그래서 우리는 무엇을할까요 ...

NukeWeaponsAdaptor-Nuke 클래스를 기반으로하지만 Weapon 인터페이스를 내 보냅니다. 이제 우리는 확실히 세상을 파괴 할 수 있습니다. 약간의 kludge처럼 보이지만 일을 작동시킵니다.


브리지 패턴은 앞까지 구현 무언가이다 - 당신은 당신이 두 개의 직교 계층 구조를 알고 있다면, 그것은 인터페이스와 클래스의 미친 번호를하지 않는 등의 방법으로 구현을 분리하는 방법을 제공합니다. 다음이 있다고 가정 해 보겠습니다.

MemoryMappedFile 및 DirectReadFile 유형의 파일 개체. 다양한 소스 (예 : Linux 대 Windows 구현 등)에서 파일을 읽을 수 있기를 원한다고 가정 해 보겠습니다. Bridge는 다음과 같은 문제를 방지하는 데 도움이됩니다.

MemoryMappedWindowsFile MemoryMappedLinuxFile DirectReadWindowsFile DirectReadLinuxFile


9
더 추상적 인 코드 목록을 사용할 수 있습니까? 예가 너무 구체적이고 혼란 스럽습니다.

36
@omouse upvoted, 예제 코드 는 실제로이 대답을 요점으로 만드는 것이 아닙니다. 주의 깊은 독자 이처럼 모두 모두, 패턴을 구별 시작하기에 충분한 포인터가있다 - 그것은 이다 좋은 대답.
Victor Farazdagi 2010

15
브리지 패턴에 대한 실제 코드 예제를 제공 할 수 있습니까?
Jaime Hablutzel 2013

2
나는 많은 사람들이 내가했던 것과 같은 방식으로이 질문에 도달했다고 상상한다. 그들은 아마도 이미 두 패턴에 대한 코드를보고 있었을 것입니다. 그러나 몇 가지 유사점을 인식하고 두 패턴을 병치함으로써 그들의 이해가 더욱 확고해질 수 있음을 깨달았습니다. Windows 및 Linux 특정 파일을 사용하는 것을 방지하는 데 도움이되는 bridge 관련 라인은 적어도 Bridge Pattern의 "Implementor"( dofactory.com/net/bridge-design-pattern )가 다른 파일과 어떻게 다른지 이해하는 데 도움 이되었습니다. "어댑터".
요르단

3
"Adapter는 설계가 완료된 후에 작동하게하고 Bridge는 작동하기 전에 작동하도록합니다." 내가 읽은 책에 전혀 명시되어 있지 않아서 구분하기 어려웠다. 내가 GOF을 읽고 추측하는 것은 ... 결국 노력이 가치가있다
알렉산더 Derck

15

http://en.wikipedia.org/wiki/Adapter_pattern

어댑터 패턴은 기존 코드가 최신 시스템 또는 인터페이스에서 작동하도록하는 것에 관한 것입니다.

다른 애플리케이션의 기존 확장 성 인터페이스에 제공하려는 회사 표준 웹 서비스 API 세트가있는 경우이를 위해 어댑터 세트를 작성하는 것을 고려할 수 있습니다. 회색 영역이 있으며 이는 파사드와 같은 다른 패턴이 유사하기 때문에 기술적으로 패턴을 정의하는 방법에 관한 것입니다.

http://en.wikipedia.org/wiki/Bridge_pattern

Bridge 패턴을 사용하면 알고리즘 또는 시스템의 대체 구현을 사용할 수 있습니다.

고전적인 Bridge 패턴 예제는 아니지만 데이터 저장소의 몇 가지 구현이 있다고 상상해보십시오. 하나는 공간에서 효율적이고 다른 하나는 원시 성능에서 효율적이며 앱이나 프레임 워크에서 모두 제공하는 비즈니스 사례가 있습니다. .

"어디에서 어떤 패턴을 사용할 수 있는지"라는 질문에 대한 답은 프로젝트에 적합한 위치입니다! 둘 중 하나를 사용해야한다고 생각하는 위치에 대한 토론을 안내하기 위해 설명 편집을 제공하는 것이 좋습니다.


14

어댑터:

  1. 구조적 패턴입니다.
  2. 두 개의 호환되지 않는 인터페이스로 작업하는 것이 유용합니다.

UML 다이어그램 : 에서 dofactory 기사 :

여기에 이미지 설명 입력

Target : 클라이언트가 사용하는 도메인 별 인터페이스를 정의합니다.

어댑터 : 인터페이스 Adaptee를 대상 인터페이스에 맞게 조정합니다.

Adaptee : 조정이 필요한 기존 인터페이스를 정의합니다.

Client : Target 인터페이스를 준수하는 객체와 협업합니다.

예:

Square와 Rectangle은 서로 다른 모양이며 각각의 area ()를 얻으려면 다른 방법이 필요합니다. 그러나 여전히 Square는 일부 속성을 변환하여 Rectangle 인터페이스에서 작동합니다.

public class AdapterDemo{
    public static void main(String args[]){
        SquareArea s = new SquareArea(4);
        System.out.println("Square area :"+s.getArea());
    }
}

class RectangleArea {
    public int getArea(int length, int width){
        return length * width;
    }
}

class SquareArea extends RectangleArea {

    int length;
    public SquareArea(int length){
        this.length = length;
    }
    public int getArea(){
        return getArea(length,length);
    }
}

다리:

  1. 구조적 패턴입니다
  2. 구현에서 추상화를 분리하고 둘 다 독립적으로 다를 수 있습니다.
  3. 상속 대신 구성을 사용했기 때문에 가능합니다.

편집 : (@quasoft 제안에 따라)

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

  1. 추상화 : 인터페이스를 정의합니다.

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

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

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

코드 조각 :

Gear gear = new ManualGear();
Vehicle vehicle = new Car(gear);
vehicle.addGear();

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

관련 게시물 :

Bridge Pattern은 언제 사용합니까? 어댑터 패턴과 어떻게 다릅니 까?

키 차이 : 에서 sourcemaking 기사

  1. 어댑터는 설계된 후에 작동합니다. Bridge는 그들이 그 전에 작동하도록 만듭니다.
  2. Bridge는 추상화와 구현이 독립적으로 변경 될 수 있도록 미리 설계되었습니다. 어댑터는 관련없는 클래스가 함께 작동하도록 개조되었습니다.

답변에 문서의 자동차 / 트럭 / 기어 예제를 포함합니다. 훌륭한 예와 비유.
quasoft

8

이 게시물은 꽤 오랫동안 사용되었습니다. 그러나 파사드가 어댑터와 다소 유사하지만 완전히 동일한 것은 아니라는 점을 이해하는 것이 중요합니다. 어댑터는 기존 클래스를 일반적으로 호환되지 않는 클라이언트 클래스에 "적응"합니다. 애플리케이션이 클라이언트로 사용하는 이전 워크 플로 시스템이 있다고 가정 해 보겠습니다. 귀사는 워크 플로우 시스템을 새로운 "호환되지 않는"시스템 (인터페이스 측면에서)으로 교체 할 수 있습니다. 대부분의 경우 어댑터 패턴을 사용하고 실제로 새 워크 플로 엔진의 인터페이스를 호출하는 코드를 작성할 수 있습니다. 브리지는 일반적으로 다른 방식으로 사용됩니다. 실제로 다른 파일 시스템 (예 : 로컬 디스크, NFS 등)과 함께 작동해야하는 시스템이있는 경우 브리지 패턴을 사용하고 하나의 추상화 계층을 만들어 모든 파일 시스템에서 작동 할 수 있습니다. 이것은 기본적으로 브리지 패턴의 간단한 사용 사례입니다. Facade와 어댑터는 일부 속성을 공유하지만facades는 일반적으로 기존 인터페이스 / 클래스를 단순화하는 데 사용됩니다 . EJB의 초기에는 EJB에 대한 지역 전화가 없었습니다. 개발자들은 항상 스텁을 가져 와서 범위를 좁혀 "의사 원격"이라고 불렀습니다. 이로 인해 종종 성능 문제가 발생했습니다 (특히 실제로 유선을 통해 호출 할 때). 숙련 된 개발자는 외관 패턴을 사용하여 클라이언트에 매우 거친 인터페이스를 제공합니다. 그런 다음이 파사드는 다른 세분화 된 메서드를 여러 번 호출합니다. 대체로 이로 인해 필요한 메서드 호출 수가 크게 줄어들고 성능이 향상되었습니다.


이 질문의 범위를 벗어난 것처럼 보이지만 Facade에 대해 어댑터 및 브리지에 가중치를 부여하는 것이 매우 적절할 수 있습니다.
Cody

1

브리지가 개선 된 어댑터입니다. Bridge는 어댑터를 포함하고 여기에 추가적인 유연성을 추가합니다. Ravindra의 답변 요소가 패턴간에 매핑되는 방법은 다음과 같습니다.

      Adapter  |    Bridge
    -----------|---------------
    Target     | Abstraction
    -----------|---------------
               | RefinedAbstraction
               |
               |   This element is Bridge specific. If there is a group of 
               |   implementations that share the same logic, the logic can be placed here.
               |   For example, all cars split into two large groups: manual and auto. 
               |   So, there will be two RefinedAbstraction classes.
    -----------|--------------- 
    Adapter    | Implementor
    -----------|---------------
    Adaptee    | ConcreteImplementor

1

상단 답변에서 @James는 GoF, page 219의 문장을 인용합니다. 여기에서 전체 설명을 재현 할 가치가 있다고 생각합니다.

어댑터 대 브리지

어댑터 및 브리지 패턴에는 몇 가지 공통 속성이 있습니다. 둘 다 다른 개체에 대한 간접 수준을 제공하여 유연성을 향상시킵니다. 둘 다 자신이 아닌 다른 인터페이스에서이 객체로 요청을 전달하는 것과 관련됩니다.

이러한 패턴의 주요 차이점은 의도에 있습니다. 어댑터는 두 개의 기존 인터페이스 간의 비 호환성을 해결하는 데 중점을 둡니다. 이러한 인터페이스를 구현하는 방법에 초점을 맞추지 않으며 독립적으로 발전 할 수있는 방법도 고려하지 않습니다. 독립적으로 디자인 된 두 개의 클래스가 하나 또는 다른 클래스를 다시 구현하지 않고 함께 작동하도록 만드는 방법입니다. 반면에 Bridge는 추상화와 그 (잠재적으로 많은) 구현을 연결합니다. 이를 구현하는 클래스를 다양화할 수있는 경우에도 클라이언트에 안정적인 인터페이스를 제공합니다. 또한 시스템이 발전함에 따라 새로운 구현을 수용합니다.

이러한 차이로 인해 어댑터와 브리지는 소프트웨어 수명주기의 다른 지점에서 자주 사용됩니다. 일반적으로 코드 복제를 방지하기 위해 호환되지 않는 두 클래스가 함께 작동해야하는 경우 어댑터가 필요합니다. 커플 링은 예측할 수 없습니다. 반대로, 브리지 사용자는 추상화에 여러 구현이 있어야하며 둘 다 독립적으로 발전 할 수 있음을 미리 이해합니다. 어댑터 패턴 은 디자인 된 후에 작동합니다 . Bridge는 그들이 존재 하기 전에 작동하도록 합니다. 그렇다고 Adapter가 Bridge보다 열등하다는 의미는 아닙니다. 각 패턴은 다른 문제를 해결할뿐입니다.


0

(일반 / 추상) 그리기 기능과 Shape를 구현하는 Circle이있는 추상 Shape 클래스가 있다고 가정합니다. 브릿지 패턴은 단순히 구현 (Circle에서 그리기)과 일반 / 추상 기능 (Shape 클래스에서 그리기)을 분리하는 양방향 추상화 접근 방식입니다.

그것은 정말로 무엇을 의미합니까? 언뜻보기에 이미 만든 것처럼 들립니다 (종속성 반전에 의해). 따라서 덜 복잡하거나 더 많은 모듈 식 코드 기반을 갖는 것에 대해 걱정할 필요가 없습니다. 그러나 그 뒤에는 조금 더 깊은 철학이 있습니다.

내 이해에서 현재 시스템 (예 : RedCircle 또는 GreenCircle)과 밀접한 관련이 있고 단일 기능 (예 : color) 만 다른 새 클래스를 추가해야 할 때 사용 패턴의 필요성이 나타날 수 있습니다. 특히 기존 시스템 클래스 (Circle 또는 Shape)가 자주 변경되고 새로 추가 된 클래스가 이러한 변경 사항에 영향을받지 않도록하려면 특히 Bridge 패턴이 필요합니다. 그래서 일반적인 그리기 기능이 새로운 인터페이스로 추상화되어 Shape 또는 Circle과 독립적으로 그리기 동작을 변경할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.