"브리지"디자인 패턴을 전혀 이해하지 못합니다. 다양한 웹 사이트를 살펴 보았지만 도움이되지 않았습니다.
아무도 이것을 이해하는 데 도움을 줄 수 있습니까?
"브리지"디자인 패턴을 전혀 이해하지 못합니다. 다양한 웹 사이트를 살펴 보았지만 도움이되지 않았습니다.
아무도 이것을 이해하는 데 도움을 줄 수 있습니까?
답변:
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*/}
Monorail
것은 실제로 두 단어가 아니기 때문에 단일 (복합) 단어 라고 생각합니다 . MonoRail은 다른 종류의 레일 대신 레일의 하위 클래스입니다. 우리가 사용하지 않을 것처럼 SunShine
또는 CupCake
, 그들은 것 Sunshine
및Cupcake
대부분의 디자인 패턴에는 유용한 이름이 있지만 "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
좋은 점 중 하나는 런타임에 구현을 동적으로로드 할 수있어 핵심 소프트웨어를 변경하지 않고도 원하는만큼 많은 테마를 추가 할 수 있다는 것입니다. 다시 말하면 나의 "구현은 추상화와 독립적으로 다를 수있다".
Win32TextboxPainter
및 Win32ListPainter
에서 Win32WidgetPainter
. 당신은 할 수 있습니다 구현 측의 상속 트리를 가지고 있지만, 그것은 (아마도 더 일반적인해야한다 StaticStyleControlPainter
, EditStyleControlPainter
그리고 ButtonStyleControlPainter
필요에 따라 대체 필요한 모든 기본 작업과 함께). 이것은 예제를 기반으로 한 실제 코드에 더 가깝습니다.
브릿지는 구체적인 구현 에서 추상화 를 분리하여 둘 다 독립적으로 달라질 수 있습니다.
브릿지는 구성을 사용하여이를 달성합니다.
잦은 혼란에 대한 추가 언급
이 패턴은 어댑터 패턴과 매우 유사합니다. 추상화 는 구현에 다른 인터페이스를 제공하고 구성을 사용 하여 구현 합니다. 그러나:
이 패턴들 사이의 주요 차이점은 그들의 의도에있다
-Gamma & al, " 디자인 패턴, 재사용 가능한 OO 소프트웨어의 요소 " , 1995
디자인 패턴에 관한이 훌륭한 책에서 저자는 또한 다음을 관찰합니다.