Pattern - Bridge
세상을 바꿀 한 문장은 무엇인가 ? 편하지 않은 흥분 상태에서 항상 열심히 일하는 것이다.
- 래리페이지 ( 구글 공동 창업자 )
의도
구현에서 추상을 분리하여, 이들이 독립적으로 다양성을 가질 수 있도록 합니다.
동기
하나의 추상적 개념이 여러가지 구현으로 구체화될 수 있을 때, 대부분은 상속을 통해서 이 문제를 해결합니다. 추상 클래스로 추상적 개념에 대한 인터페이스를 정의하고, 구체적인 서브 클래스에서 서로 다른 방식으로 이들 인터페이스를 구현합니다. 그러나 이 방법만으로는 충분한 융통성을 얻을 수 없습니다. 상속은 구현과 추상적 개념을 영구적으로 종속시키기 때문에, 추상적 개념과 구현을 분리해서 재사용하거나 수정, 확장하기가 쉽지 않습니다.
활용성
- 추상적 개념과 이에 대한 구현 사이의 지속적인 종속 관계를 피하고 싶을 때, 이를테면, 런타임에 구현 방법을 선택하거나 구현 내용을 변경하고 싶을 때가 여기에 해당합니다.
- 추상적 개념과 구현 모두가 독립적으로 서브클래싱을 통해 확장되어야 할 때, 이때, 가교 패턴은 개발자가 구현을 또 다른 추상적 개념과 연결할 수 있게 할 뿐 아니라, 각각을 독립적으로 확장가능하게 합니다.
- 추상적 개념에 대한 구현 내용을 변경하는 것이 다른 관련 프로그램에 아무런 영향을 주지 않아야 할 때, 즉, 추상적 개념에 해당하는 클래스를 사용하는 코드들은 구현 클래스가 변경되었다고 해서 다시 컴파일 되지 않아야 합니다.
항목별 설명
-
Abstraction
Window
추상적 개념에 대한 인터페이스를 제공하고 객체 구현자(implementer)에 대한 참조자를 관리합니다. -
RefinedAbstraction
IconWindow
추상적 개념에 정의된 인터페이스를 확장합니다. -
implementer
WindowImp
구현 클래스에 대한 인터페이스를 제공합니다. 다시 말해, 실질적인 구현을 제공한 서브 클래스 들에 공동적인 연산의 시그너처 만을 정의합니다. 이 인터페이스는 Abstraction 클래스에 정의된 인터페이스에 정확하게 대응할 필요가 없습니다. 즉, 두 인터페이스를 서로 다른 형태 일 수 있습니다. 일반적으로 implementer 인터페이스는 기본적인 구현 연산을 수행하고, Abstraction는 더 추상화된 서비스 관점의 인터페이스를 제공합니다. -
ConcreteImplementer
XWindowImp, PMWindowImp
implementer 인터페이스를 구현하는 것으로 실제적인 구현 내용을 담았습니다.
코드 예제 - 기본
package DesignPattern.gof_bridge.sample_01;
public class Client {
public static void main(String[] args) {
Abstraction abstraction = new RefineAbstraction(new ConcreteImplementer1());
abstraction.workwithImplementer();
}
}
package DesignPattern.gof_bridge.sample_01;
public interface Implementer {
public void implement();
}
package DesignPattern.gof_bridge.sample_01;
// 서비스를 위한 실질적인 처리 방식
public class ConcreteImplementer1 implements Implementer {
public void implement() {
System.out.println("전혀 다른 Implementer 1에 대한 프로세스 ");
}
}
package DesignPattern.gof_bridge.sample_01;
// 서비스를 위한 실질적인 처리 방식
public class ConcreteImplementer2 implements Implementer {
public void implement() {
System.out.println("전혀 다른 Implementer 2에 대한 프로세스 ");
}
}
package DesignPattern.gof_bridge.sample_01;
// 추상화된 서비스의 관점에서 Abstraction 구성
public abstract class Abstraction {
protected final Implementer implementer;
public Abstraction(Implementer implementer){
this.implementer = implementer;
}
public abstract void workwithImplementer();
}
package DesignPattern.gof_bridge.sample_01;
// 추상화된 서비스의 실질적인 처리
public class RefineAbstraction extends Abstraction {
public RefineAbstraction(Implementer implementer){
super(implementer);
}
@Override
public void workwithImplementer() {
implementer.implement();
}
}
코드 예제 - 추가 ( 다른 방식 )
/** "Implementor" */
interface BankAPI
{
public void withdraw();
}
/** "ConcreteImplementor" 1/2 */
class KookminBankAPI1 implements BankAPI
{
public void withdraw()
{
System.out.printf("API1.withdraw");
}
}
/** "ConcreteImplementor" 2/2 */
class HanaBankAPI2 implements BankAPI
{
public void withdraw()
{
System.out.printf("API2.withdraw");
}
}
/** "Abstraction" */
interface Developer
{
public void withdraw();
}
/** "Refined Abstraction" */
class APIDeveloper implements Developer
{
private BankAPI bankAPI;
public APIDeveloper(BankAPI bankAPI)
{
this.bankAPI = bankAPI;
}
// low-level i.e. Implementation specific
public void withdraw()
{
bankAPI.withdraw(;
}
}
/** "Client" */
class BridgePattern {
public static void main(String[] args)
{
Developer[] bankDevelopers = new Developer[2];
// 객체의 생성 시점에 역할이 정해지며, 이는 객체의 행동시점에 따라 달라지는 전략 패턴과는 차이가 있다.
bankDevelopers[0] = new APIDeveloper(new KookminBankAPI1());
bankDevelopers[1] = new APIDeveloper(new HanaBankAPI2());
for (Developer developer : bankDevelopers)
{
developer.withdraw();
}
}
}
Kotlin - Bridge
package bong.lines.patterns.bridge.inf
interface Implementer {
fun implement()
}
package bong.lines.patterns.bridge.abstract
import bong.lines.patterns.bridge.inf.Implementer
abstract class Abstraction(val implementer: Implementer) {
abstract fun workWithImplementer()
}
package bong.lines.patterns.bridge.impl
import bong.lines.patterns.bridge.inf.Implementer
class ConcreteImplementer1 : Implementer {
override fun implement() {
print("전혀 다른 Implementer 1에 대한 프로세스 ")
}
}
package bong.lines.patterns.bridge.impl
import bong.lines.patterns.bridge.inf.Implementer
class ConcreteImplementer2 : Implementer {
override fun implement() {
print("전혀 다른 Implementer 2에 대한 프로세스 ")
}
}
package bong.lines.patterns.bridge.impl
import bong.lines.patterns.bridge.abstract.Abstraction
import bong.lines.patterns.bridge.inf.Implementer
class RefineAbstraction(implementer: Implementer) : Abstraction(implementer) {
override fun workWithImplementer() {
implementer.implement()
}
}
package bong.lines.patterns.bridge
import bong.lines.patterns.bridge.abstract.Abstraction
import bong.lines.patterns.bridge.impl.ConcreteImplementer1
import bong.lines.patterns.bridge.impl.RefineAbstraction
fun main() {
var abstraction: Abstraction = RefineAbstraction(ConcreteImplementer1())
abstraction.workWithImplementer()
}