Bridge는 큰 클래스 또는 밀접하게 관련된 클래스 집합을 서로 독립적으로 개발할 수 있는 추상화 및 구현이라는 두개의 개별 계층으로 분할 할 수 있는 구조적 디자인 패턴입니다.

한 쌍의 subclasses인 Circle 및 Square가있는 Shape 클래스가 있다고 가정 해 보겠습니다. 이 클래스 계층 구조를 확장하여 색상을 통합하려고 하므로 빨강 및 파랑 모양 subclasses를 만들 계획입니다. 그러나 이미 2개의 subclasses가 있으므로 BlueCircle 및 RedSquare와 같은 4개의 클래스 조합을 만들어야합니다.

새로운 모양 유형과 색상을 계층 구조에 추가하면 기하급수적으로 늘어납니다. 예를 들어 삼각형 모양을 추가하려면 각 색상에 하나씩 두 개의 하위 subclasses를 도입해야합니다. 그 후 새 색상을 추가하려면 각 모양 유형에 대해 하나씩 세 개의 subclasses를 만들어야 합니다. 더 멀리 갈수록 더 나빠집니다.
이 문제는 모양 클래스를 양식 및 색상의 두 가지 독립된 차원으로 확장하려고 하기 때문에 발생합니다. 이것은 클래스 상속과 관련된 매우 일반적인 문제입니다.
Bridge 패턴은 상속에서 개체 구성으로 전환하여 이 문제를 해결하려고 합니다. 이것이 의미하는 바는 차원 중 하나를 별도의 클래스 계층으로 추출하여 원래 클래스가 하나의 클래스 내에 모든 상태 및 동작을 갖는 대신 새 계층의 객체를 참조하도록 한다는 것입니다.

이 접근 방식에 따라 색상 관련 코드를 Red와 Blue의 두 가지 subclass가 있는 자체 클래스로 추출 할 수 있습니다. 그런 다음 Shape 클래스는 색상 객체 중 하나를 가리키는 참조 필드를 가져옵니다. 이제 모양은 색상 관련 작업을 연결된 색상 객체에 위임 할 수 있습니다. 이 참조는 Shape 클래스와 Color 클래스 사이의 다리 역할을합니다. 이제부터는 새 색상을 추가 할 때 모양 계층을 변경할 필요가 없으며 그 반대의 경우도 마찬가지입니다.
GoF 책은 Bridge 정의의 일부로 Abstraction and Implementation이라는 용어를 소개합니다. 제 생각에는 용어가 너무 학문적으로 들리며 패턴이 실제보다 더 복잡해 보입니다. 모양과 색상이있는 간단한 예를 읽은 후 GoF 책의 무서운 단어 뒤에 숨겨진 의미를 해독 해 봅시다.
추상화 (인터페이스라고도 함)는 일부 엔터티에 대한 높은 수준의 제어 계층입니다. 이 레이어는 자체적으로 실제 작업을 수행해서는 안됩니다. 작업을 구현 계층 (플랫폼이라고도 함)에 위임해야합니다.
프로그래밍 언어의 인터페이스 또는 추상 클래스에 대해 이야기하는 것이 아닙니다. 이것들은 같은 것이 아닙니다.
실제 애플리케이션에 대해 이야기 할 때 추상화는 그래픽 사용자 인터페이스 (GUI)로 나타낼 수 있으며 구현은 GUI 계층이 사용자 상호 작용에 대한 응답으로 호출하는 기본 운영 체제 코드 (API) 일 수 있습니다.
일반적으로 이러한 앱을 두 개의 독립적인 방향으로 확장 할 수 있습니다.
최악의 시나리오에서 이 앱은 수백 개의 조건문이 코드 전체에서 다양한 API와 다양한 유형의 GUI를 연결하는 거대한 스파게티 그릇처럼 보일 수 있습니다.

특정 인터페이스-플랫폼 조합과 관련된 코드를 별도의 클래스로 추출하여 이 혼란에 질서를 가져올 수 있습니다. 그러나 곧 이러한 수업이 많이 있다는 것을 알게 될 것입니다. 새로운 GUI를 추가하거나 다른 API를 지원하려면 더 많은 클래스를 생성해야 하기 때문에 클래스 계층 구조가 기하 급수적으로 증가 할 것입니다.
이 문제를 Bridge 패턴으로 해결해 보겠습니다. 클래스를 두 개의 계층으로 나눌 것을 제안합니다.

추상화 개체는 앱의 모양을 제어하여 실제 작업을 연결된 구현 개체에 위임합니다. 공통 인터페이스를 따르는 한 서로 다른 구현을 상호 교환 할 수 있으므로 동일한 GUI가 Windows 및 Linux에서 작동 할 수 있습니다.
결과적으로 API 관련 클래스를 건드리지 않고도 GUI 클래스를 변경할 수 있습니다. 또한 다른 운영 체제에 대한 지원을 추가하려면 구현 계층 구조에서 하위 클래스를 만들어야합니다.

이 예제는 Bridge 패턴이 장치와 원격 제어를 관리하는 앱의 monolithic 코드를 분할하는데 어떻게 도움이 되는지 보여줍니다. Device 클래스는 구현으로 작동하는 반면 Remote는 추상화로 작동합니다.

기본 원격 제어 클래스는 장치 개체와 연결하는 참조 필드를 선언합니다. 모든 리모컨은 일반 장치 인터페이스를 통해 장치와 작동하므로 동일한 리모컨이 여러 장치 유형을 지원할 수 있습니다.
장치 클래스와 독립적으로 원격 제어 클래스를 개발할 수 있습니다. 필요한 것은 새 원격 subclass를 만드는 것입니다. 예를 들어 기본 리모컨에는 버튼이 두 개만 있을 수 있지만 추가 배터리 또는 터치 스크린과 같은 추가 기능을 사용하여 확장 할 수 있습니다.
클라이언트 코드는 원격의 생성자를 통해 원하는 유형의 원격 제어를 특정 장치 개체와 연결합니다.
// The "abstraction" defines the interface for the "control"
// part of the two class hierarchies. It maintains a reference
// to an object of the "implementation" hierarchy and delegates
// all of the real work to this object.
class RemoteControl is
protected field device: Device
constructor RemoteControl(device: Device) is
this.device = device
method togglePower() is
if (device.isEnabled()) then
device.disable()
else
device.enable()
method volumeDown() is
device.setVolume(device.getVolume() - 10)
method volumeUp() is
device.setVolume(device.getVolume() + 10)
method channelDown() is
device.setChannel(device.getChannel() - 1)
method channelUp() is
device.setChannel(device.getChannel() + 1)
// You can extend classes from the abstraction hierarchy
// independently from device classes.
class AdvancedRemoteControl extends RemoteControl is
method mute() is
device.setVolume(0)
// The "implementation" interface declares methods common to all
// concrete implementation classes. It doesn't have to match the
// abstraction's interface. In fact, the two interfaces can be
// entirely different. Typically the implementation interface
// provides only primitive operations, while the abstraction
// defines higher-level operations based on those primitives.
interface Device is
method isEnabled()
method enable()
method disable()
method getVolume()
method setVolume(percent)
method getChannel()
method setChannel(channel)
// All devices follow the same interface.
class Tv implements Device is
// ...
class Radio implements Device is
// ...
// Somewhere in client code.
tv = new Tv()
remote = new RemoteControl(tv)
remote.togglePower()
radio = new Radio()
remote = new AdvancedRemoteControl(radio)
일부 기능의 여러 변형이있는 모 놀리 식 클래스를 나누고 구성하려는 경우 (예 : 클래스가 다양한 데이터베이스 서버에서 작동 할 수있는 경우) Bridge 패턴을 사용하십시오.
클래스가 커질수록 어떻게 작동하는지 파악하기가 더 어려워지고 변경하는 데 더 오래 걸립니다. 기능 변형 중 하나를 변경하려면 전체 클래스를 변경해야 할 수 있으며, 이로 인해 종종 오류가 발생하거나 몇 가지 중요한 부작용이 해결되지 않습니다.
Bridge 패턴을 사용하면 모 놀리 식 클래스를 여러 클래스 계층으로 분할 할 수 있습니다. 그런 다음 다른 계층의 클래스와 독립적으로 각 계층의 클래스를 변경할 수 있습니다. 이 접근 방식은 코드 유지 관리를 단순화하고 기존 코드를 손상시킬 위험을 최소화합니다.
여러 직교 (독립) 차원에서 클래스를 확장해야하는 경우 패턴을 사용하십시오.
Bridge는 각 차원에 대해 별도의 클래스 계층을 추출 할 것을 제안합니다. 원래 클래스는 모든 작업을 자체적으로 수행하는 대신 해당 계층에 속한 개체에 관련 작업을 위임합니다.
런타임에 구현을 전환 할 수 있어야하는 경우 Bridge를 사용하십시오.
선택 사항이지만 Bridge 패턴을 사용하면 추상화 내부의 구현 개체를 바꿀 수 있습니다. 필드에 새 값을 할당하는 것만 큼 쉽습니다.
그건 그렇고,이 마지막 항목은 많은 사람들이 Bridge를 전략 패턴과 혼동하는 주된 이유입니다. 패턴은 클래스를 구조화하는 특정 방법 이상이라는 것을 기억하십시오. 또한 의도와 해결중인 문제를 전달할 수 있습니다.
O 플랫폼에 독립적 인 클래스와 앱을 만들 수 있습니다.
O 클라이언트 코드는 높은 수준의 추상화와 함께 작동합니다. 플랫폼 세부 정보에 노출되지 않습니다.
O 개방 / 폐쇄 원칙. 서로 독립적으로 새로운 추상화와 구현을 도입 할 수 있습니다.
O 단일 책임 원칙. 추상화의 고수준 논리와 구현의 플랫폼 세부 사항에 집중할 수 있습니다.
X 응집력이 높은 클래스에 패턴을 적용하여 코드를 더 복잡하게 만들 수 있습니다.