브릿지 패턴(Bridge Pattern)

INSANEZINDOL·2022년 3월 2일
0

Design Pattern

목록 보기
9/10
post-thumbnail

개요

'기능의 클래스 계층' 과 '구현의 클래스 계층'간에 다리(Bridge)를 놓는 역할을 하는 패턴입니다.

클래스 계층의 두 가지 역할

기능의 클래스 계층

  • 기본적인 사칙연산들을 포함하고 있는 Calculator라는 클래스가 있다고 가정합니다. 그런데 여기에 제곱,거듭제곱, 미분,적분 등 다양한 수학공식기능을 추가하고 싶을 때 우리는 Calculator를 상속받는 확장클래스 공학용계산기 EngineeringCalculator를 만듭니다. 이 클래스는 여러가지 공학용 '기능'을 추가하기 위해 만들어진 계층입니다.
    이러한 클래스 계층을 '기능의 클래스 계층' 이라 합니다.
    EnginneringCalculator 클래스에서 또 다시 새로운 기능을 추가하고 싶으면 강화된 공학용 계산기( EnhancedEnginneringCalculator )으로 또 확장할 수 있습니다.
    일반적으로 클래스 계층은 너무 깊게 만들지 않는것이 좋습니다.

구현의 클래스 계층

  • Template Method Pattern에서 우리는 추상 클래스의 역할에 대해 알아봤습니다. 추상 클래스에서는 추상 메소드를 선언해 인터페이스(API)를 명세한 뒤 하위클래스에서 인터페이스를 구현합니다. 이처럼 상위클래스와 하위클래스의 역할분담은 상위클래스를 좀 더 유연하고 교체가능하게 만듭니다.
    다시 주제로 돌아와 상위 클래스 AbstractClass의 추상메소드를 구현하는 하위 클래스를 ConcreteClass라 할 경우 클래스 계층이 생성됩니다.
    하지만 여기서의 클래스 계층은 기능을 추가하거나 새로운 메소드를 추가하기 위한 것이 아닌 '역할 분담'을 위해 클래스 계층이 사용됩니다.

    →상위 클래스는 추상 메소드에 의해 인터페이스(API)를 명세한다.
    →하위 클래스는 구상 메소드에 의해 그 인터페이스(API)를 구현한다.

  • 이러한 클래스 계층을 '구현의 클래스 계층' 이라 합니다. 상위 클래스의 새로운 하위 구현 클래스를 만들게 되면 클래스 계층은 다시 한 번 변합니다.

클래스 계층의 혼재와 클래스 계층의 분리

'기능의 클래스 계층' 과 '구현의 클래스 계층'에 대해 알아봤습니다. 이제 하위 클래스를 만들기 전, 내가 만들고자 클래스가 구현을 위함인가, 기능의 확장을 위함인가를 고려해야 합니다. 클래스 계층이 하나라면 기능의 클래스 계층과 구현의 클래스 계층이 하나의 계층구조안에서 혼재하게 됩니다. 그렇게 될 경우 클래스 계층이 복잡해져서 예측을 어렵게하고, 하위 클래스를 만들고자 할 때 클래스 계층의 어디에 만들면 좋을지 더 복잡해지게 됩니다.

그렇기 때문에 두 개의 계층을 독립 된 클래스 계층으로 분리합니다. 단순히 분리만 해버릴 경우 흩어져버리기 때문에 두 개의 클래스 계층 사이에 다리를 놓는 일이 필요한데, 이를 Bridge Pattern을 통해 해결합니다.

역할

1. Abstaction(추상화)의 역할

'기능의 클래스 계층'의 최상위 클래스 입니다. Implementor 역할의 메소드를 사용해서 기본적인 기능만이 기술되어 있는 클래스.
이 인스턴스는 Implementor 역할을 가지고 있습니다. 예제에서는 Display 클래스가 해당 역할을 합니다.

2. RefineAbstaction(개선된 추상화)의 역할

Abstaction 역할에 대해 기능을 추가한 역할.
예제에서는 CountDisplay가 해당됩니다.

3. Implementor(구현자)의 역할

'구현의 클래스 계층'의 최상위 클래스입니다. Abstaction역할의 인터페이스(API)를 구현하기 위한 메소드를 규정하는 역할입니다.
예제에서는 DIsplayImpl 클래스가 이 역할을 합니다

4. Concrete Implementor(구체적인 구현자)의 역할

Implementor역할의 인터페이스(API)를 구체적으로 구현하는 역할입니다.
예제에서는 StringDisplayImpl 이 해당됩니다.

참고

분리를 해 두면 확장이 편해진다.

  • Bridge Pattern의 가장 큰 특징은 '기능의 클래스 계층(Abstraction)과 '구현의 클래스 계층(Implementor)의 분리입니다.
    이 두 개의 클래스 계층을 분리해 두면 각각의 클래스 계층을 독립적으로 확장할 수 있습니다. 더하여 유지보수 및 추가계약에 따른 업그레이드도 편리해집니다.
    예를들어 요구사항으로 기능의 추가가 왔다면 Abstractor쪽에 클래스를 추가만 해주면 되고, 구현의 상세로직이 변경되면 Implementor쪽만 변경 혹은 추가해주면 됩니다.
    양 측이 각각 기능추가 및 구현부분의 변경이 일어나더라도 다른 계층에서의 수정이 필요가 없습니다.

견고한 상속과 느슨한 위임

  • 가장 흔하게 사용하는 클래스 확장 방법은 '상속' 입니다. (...class name extends xxxxx{...}) 이러한 상속관계는 소스를 고쳐쓰지 않는 한 바꿀 수 없는 견고한 연결이 됩니다. 그 말은 프로그램의 필요에 따라 클래스 간의 관계를 유연하게 바꾸고 싶을 때 상속을 사용하는 것은 부적절하다는 뜻입니다. 교체할 때마다 소스 코드를 변경할 수는 없기 때문입니다.
    위 예제 코드의Abstraction(Display)는 Implementor(DIsplayImpl)을 인자값으로 위임받아서 사용합니다.
    (ex: open(){ impl.rawOpen();}) 이렇게 상속이 아닌 위임을 하게 될 경우 두 클래스간의 결합도는 낮아지기 때문에 언제든지 impl의 인자로 다른 Implementor를 위임해서 사용할 수 있습니다. 현재 예제에서는 StringDisplayImpl이라는 Concrete Implementor를 위임하고 있지만, 해당 클래스 이외에 다른 Concrete Implementor가 있다면 해당 인스턴스를 다른 Abstraction(DIsplay or CountDisplay)에 전달하면 구현이 확실히 교체됩니다.
profile
Java Backend Developer

0개의 댓글