브릿지 디자인 패턴 이해


24

"브리지"디자인 패턴을 전혀 이해하지 못합니다. 다양한 웹 사이트를 살펴 보았지만 도움이되지 않았습니다.

아무도 이것을 이해하는 데 도움을 줄 수 있습니까?


2
나는 그것을 이해하지 못한다. 답변을 기대하겠습니다 :)
바이올렛 기린

디자인 패턴을 설명하는 웹 사이트와 책이 많이 있습니다. 이미 작성된 내용을 반복하는 데 가치가 있다고 생각하지 않습니다. 어쩌면 특정 질문을 할 수 있습니다. 다른 소스와 예제를 계속 전환하면서 이해하는 데 시간이 걸렸습니다.
헬레나

답변:


16

OOP에서는 다형성을 사용하므로 추상화가 여러 구현을 가질 수 있습니다. 다음 예제를 보자.

//trains abstraction
public interface Train
{ 
    move();
}
public class MonoRail:Train
{
    public override move()
    {
        //use one track;
    }
}
public class Rail:Train
{
    public override move()
    {
        //use two tracks;
    }
}

새로운 요구 사항이 도입되어 열차의 가속 관점을 가져와야하므로 코드를 다음과 같이 변경하십시오.

    public interface Train
    { 
        void move();
    }
    public class MonoRail:Train
    {
        public override void move()
        {
            //use one track;
        }
    }
    public class ElectricMonoRail:MonoRail
    {
        public override void move()
        {
            //use electric engine on one track.
        }
    }
    public class DieselMonoRail: MonoRail
    {
        public override void move()
        {
            //use diesel engine on one track.
        }
    }
    public class Rail:Train
    {
        public override void move()
        {
            //use two tracks;
        }
    }
    public class ElectricRail:Rail
    {
        public override void move()
        {
            //use electric engine on two tracks.
        }
    }
    public class DieselRail: Rail
    {
        public override void move()
        {
            //use diesel engine on two tracks.
        }
    }

위의 코드는 유지 관리 할 수없고 재사용 성이 부족합니다 (동일한 트랙 플랫폼에서 가속 메커니즘을 재사용 할 수 있다고 가정). 다음 코드는 브릿지 패턴을 적용하고 두 개의 서로 다른 추상화 ( 기차 수송가속)를 구분 합니다.

public interface Train
{ 
    void move(Accelerable engine);
}
public interface Accelerable
{
    public void accelerate();
}
public class MonoRail:Train
{
    public override void move(Accelerable engine)
    {
        //use one track;
        engine.accelerate(); //engine is pluggable (runtime dynamic)
    }
}
public class Rail:Train
{
    public override void move(Accelerable engine)
    {
        //use two tracks;
        engine.accelerate(); //engine is pluggable (runtime dynamic)
    }
}
public class ElectricEngine:Accelerable{/*implementation code for accelerable*/}
public class DieselEngine:Accelerable{/*implementation code for accelerable*/}

3
아주 좋은 예입니다. 저는 2 센트를 더할 것입니다 : 이것은 상속보다 구성을 선호하는 아주 좋은 예입니다
zzfima

1
가치가있는 Monorail것은 실제로 두 단어가 아니기 때문에 단일 (복합) 단어 라고 생각합니다 . MonoRail은 다른 종류의 레일 대신 레일의 하위 클래스입니다. 우리가 사용하지 않을 것처럼 SunShine또는 CupCake, 그들은 것 SunshineCupcake
ErikE

이 두 줄의 서로 다른 추상화, 기차 수송 및 가속이 도움이되고, 두 계층이 무엇인지, 그리고 우리가 해결하려고하는 것은 독립적으로 다양하게 만드는 것입니다.
wangdq

11

대부분의 디자인 패턴에는 유용한 이름이 있지만 "Bridge"라는 이름은 그 기능과 관련하여 직관적이지 않은 것으로 생각됩니다.

개념적으로 클래스 계층 구조에서 사용되는 구현 세부 정보를 일반적으로 자체 계층 구조를 가진 다른 개체로 푸시합니다. 그렇게함으로써 구현 세부 사항에 대한 밀접한 종속성을 제거하고 해당 구현 세부 사항을 변경할 수 있습니다.

소규모로, 나는 당신이 새로운 행동을 꽂을 수있는 방식으로 전략 패턴을 사용하는 것에 비유합니다. 그러나 전략에서 흔히 볼 수있는 것처럼 알고리즘을 래핑하는 대신 구현 객체는 일반적으로 더 많은 기능으로 채워집니다. 그리고 개념을 전체 클래스 계층에 적용하면 더 큰 패턴이 브리지가됩니다. (다시, 이름을 미워하십시오).

매일 사용하는 패턴은 아니지만 다중 상속이 필요할 때 발생할 수있는 클래스 급증을 관리 할 때 도움이됩니다.

실제 예는 다음과 같습니다.

디자인 화면에서 컨트롤을 삭제하고 구성 할 수있는 RAD 도구가 있으므로 다음과 같은 개체 모델이 있습니다.

Widget // base class with design surface plumbing
+ Top
+ Left
+ Width
+ Height
+ Name
+ SendToBack
+ BringToFront
+ OnPropertyEdit
+ OnSelect
+ Validate
+ ShowEditor
+ Paint
+ Etc

TextboxWidget : Widget // text box specific
+ Text
+ MaxLength
+ Font
+ ShowEditor // override base to show a property editor form specific to a Textbox
+ Paint // override to render a textbox onto the surface    
+ Etc

ListWidget : Widget // list specific
+ Items
+ SelectedItem
+ ShowEditor // override base to show a property editor form specific to a List
+ Paint // override to render a list onto the surface
+ Etc

그리고 아마도 십여 개의 컨트롤이 있습니다.

그러나 여러 테마 (look-n-feels)를 지원하기위한 새로운 요구 사항이 추가되었습니다. 이제 우리는 다음과 같은 주제를 가지고 있다고 가정 해 봅시다 : Win32, WinCE, WinPPC, WinMo50, WinMo65. 각 테마는 DefaultFont, DefaultBackColor, BorderWidth, DrawFrame, DrawScrollThumb 등과 같은 렌더링 관련 작업에 대해 서로 다른 값 또는 구현을 갖습니다.

다음과 같은 객체 모델을 만들 수 있습니다.

Win32TextboxWidget : TextboxWidget

Win32ListWidget : ListWidget

하나의 제어 유형의 경우 등

WinCETextboxWidget : TextboxWidget

WinCEListWidget : ListWidget

등 서로 제어 유형 (다시)

아이디어 수 – 위젯 수에 테마 수를 곱한 클래스 급증. 이는 RAD 디자이너가 각각의 모든 테마를 인식하게하여 복잡해집니다. 또한 새로운 테마를 추가하면 RAD 디자이너가 수정됩니다. 또한 테마 내에서 상속하는 것이 좋은 일반적인 구현이 많이 있지만 컨트롤은 이미 공통 기반 ( Widget) 에서 상속됩니다 .

대신 내가 한 일은 테마를 구현하는 별도의 객체 계층을 만드는 것입니다. 각 위젯은 렌더링 작업을 구현하는 객체에 대한 참조를 보유합니다. 많은 텍스트에서이 클래스에는 접미사가 붙었 Impl지만 이름 지정 규칙에서 벗어났습니다.

이제 내 TextboxWidget모습은 다음과 같습니다.

TextboxWidget : Widget // text box specific
+ Text
+ MaxLength
+ Font
+ ShowEditor
+ Painter // reference to the implementation of the widget rendering operations
+ Etc

그리고 저는 다양한 화가들이 테마별베이스를 상속 받도록 할 수 있습니다.

Win32WidgetPainter
+ DefaultFont
+ DefaultFontSize
+ DefaultColors
+ DrawFrame
+ Etc

Win32TextboxPainter : Win32WidgetPainter

Win32ListPainter : Win32WidgetPainter

좋은 점 중 하나는 런타임에 구현을 동적으로로드 할 수있어 핵심 소프트웨어를 변경하지 않고도 원하는만큼 많은 테마를 추가 할 수 있다는 것입니다. 다시 말하면 나의 "구현은 추상화와 독립적으로 다를 수있다".


이것이 브리지 패턴이라고 생각되는 방법을 이해하지 못합니까? 위젯 계층 구조에 새 구성 요소를 추가하면 해당 새 위젯을 모든 페인터 (Win32NewWidgetPainter, PPCNewWidgetPainter)에 추가해야합니다. 이것은 독립적으로 성장하는 두 개의 계층이 아닙니다. 적절한 브릿지 패턴을 위해서는 각 위젯에 대해 PlatformWidgetPainter 클래스를 서브 클래스 화하지 말고 위젯 "드로우 디스크립터"를 수신하십시오.
Mazyod

의견을 보내 주셔서 감사합니다. 내가이 게시 된 것을 년 전, 나는 그것을 잘 다리를 설명합니다 말을 현재 검토 할 때까지 내가 파생 마지막 비트 Win32TextboxPainterWin32ListPainter 에서 Win32WidgetPainter. 당신은 할 수 있습니다 구현 측의 상속 트리를 가지고 있지만, 그것은 (아마도 더 일반적인해야한다 StaticStyleControlPainter, EditStyleControlPainter그리고 ButtonStyleControlPainter필요에 따라 대체 필요한 모든 기본 작업과 함께). 이것은 예제를 기반으로 한 실제 코드에 더 가깝습니다.
tcarvin

3

브릿지는 구체적인 구현 에서 추상화 를 분리하여 둘 다 독립적으로 달라질 수 있습니다.

  • 서브 클래 싱으로 추상화를 세분화
  • 추상화 나 개선 사항을 알 필요없이 서브 클래 싱을 통해 다른 구현을 제공합니다.
  • 필요한 경우 런타임에 가장 적합한 구현을 선택하십시오 .

브릿지는 구성을 사용하여이를 달성합니다.

  • 추상화는 구현 객체를 참조 (참조 또는 포인터)
  • 추상화와 그 개선은 구현 인터페이스 만 알았습니다.

여기에 이미지 설명을 입력하십시오

잦은 혼란에 대한 추가 언급

이 패턴은 어댑터 패턴과 매우 유사합니다. 추상화구현에 다른 인터페이스를 제공하고 구성을 사용 하여 구현 합니다. 그러나:

이 패턴들 사이의 주요 차이점은 그들의 의도에있다
-Gamma & al, " 디자인 패턴, 재사용 가능한 OO 소프트웨어의 요소 " , 1995

디자인 패턴에 관한이 훌륭한 책에서 저자는 또한 다음을 관찰합니다.

  • 비 호환성이 발견되고 커플 링을 예측할 수없는 경우 어댑터가 종종 사용됩니다.
  • 교량은 클래스가 독립적으로 발전 할 것으로 예상 될 때 설계 초기부터 사용됩니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.