Bridge_Pattern
Download
Report
Transcript Bridge_Pattern
http://cutewebi.tistory.com
[email protected]
김희정
BRIDGE PATTERN
Bridge Pattern
현실 세계의 다리가 강으로 나누어진 양쪽
장소를 연결하는 것처럼 ,
Bridge 패턴도 두 장소를 연결하는 역할.
Bridge 패턴이 다리를 놓을 곳?
'기능의 클래스 계층’
'구현의 클래스 계층’
새로운 '기능'을 추가하고 싶을때
어떤 클래스 Something에 새로운 기능을 추가하려고
할때
(새로운 메소드를 추가하려고 할 때)
Something의 하위 클래스(자식 클래스, 파생 클래스,
확장 클래스)로서 SomethingGood 클래스를 만든다.
이것으로 소규모의 클래스 계층이 발생한다.
Something
+ SomethingGood
새로운 '기능'을 추가하고 싶을때
상위 클래스 : 기본적인 기능을 가지고 있음.
하위 클래스 : 새로운 기능을 추가.
'기능의 클래스 계층'이라고 함.
SomethingGood 클래스에 또 다시 새로운 기능을 추가하고 싶으면
SomethingGood 클래스의 하위 클래스로서
SomethingBetter 클래스를 만든다.
이것으로 기능의 클래스 계층이 좀 더 깊어짐.
일반적으로 클래스 계층은 너무 깊게 하지 않는 것이 좋다.
Something
+ SomethingGood
+ SomethingBetter
새로운 '구현'을 추가하고 싶을 때
추상 클래스가 일련의 메소드들을 추상 메
소드로서 선언하고 인터페이스(API)를 규정.
하위 클래스 쪽에서 그 추상 메소드를 실제
로 구현.
이와 같은 상위 클래스와 하위 클래스의 역
활 분담에 의해 부품으로서의 가치(교환 가
능성)가 높은 클래스를 만들 수 있다.
새로운 '구현'을 추가하고 싶을 때
예를 들면 상위 클래스 AbstractClass의 추상
메소드를 구현하는 하위 클래스를
ConcreteClass로 하면
다음과 같은 소규모의 클래스 계층이 만들
어진다.
AbstractClass
+ ConcreteClass
새로운 '구현'을 추가하고 싶을 때
그렇지만 여기서 사용되고 있는 클래스 계층은 기능을
추가하기 위한 것이 아니라
역할 분담을 위해 클래스 계층이 사용.
상위 클래스 : 추상 메소드에 의해 인터페이스(API)를 규정.
하위 클래스 : 구현 메소드에 의해 그 인터페이스(API)를 구현.
AbstractClass의 다른 구현을 만들고 싶으면
하위 클래스를 AnotherConcreteClass로 한다.
AbstractClass
+ ConcreteClass
+ Another ConcreteClass
Example
기능(추상화)
구현
클래스의 역활
Client의 역할
Bridge 패턴을 사용하는 객체.
Abstraction(추상화)의 역할
'기능의 클래스 계층'의 최상위에 있는 클래스.
Implementor 역할의 메소드를 사용해서 기본적인 기능만 기술되어 있
는 클래스. (이 인스턴스는 Implementor 역할을 가짐)
RefinedAbstraction(개선된 추상화)의 역할
Abstraction 역할에 기능을 추가한 역할.
Implementor(구현자)의 역할
'구현의 클래스 계층'의 최상위에 있는 클래스.
Abstraction 역할의 인터페이스(API)를 구현하기 위한 메소드를 규정
하는 역할.
ConcreteImplementor(구체적인 구현자)의 역할
Implementor 역할의 인터페이스(API)를 구체적으로 구현하는 역할.
Bridge Pattern
클래스의 구현으로부터 인터페이스를 분리
하는데 사용.
추상화 정도에 의한 계층으로 구분되어 있
고
이를 구현하는데 있어 몇 개의 계층으로 나
누는 경우에 유용한 패턴.
추상화 정도와 구현에 따라 완전히 구별되
는 여러 클래스로 나누기 보다는
이를 동적으로 조합되는 몇 개의 상이한 클
래스로 관리.
Bridge 패턴을 사용하는 경우
구현을 run-time binding 할 경우
인터페이스의 결합과 여러가지의 구현으로
클래스를 많이 만들어야 하는 경우
여러 객체에서 구현을 공유하려고 할 때
클래스 구조를 수직으로 나눌 필요가 있을
때
구성 요소
클래스의 인터페이스를 정의하는 추상화
(Abstraction)
해당 인터페이스를 상속하고 구현하는 정제
된 추상화(Refined Abstraction)
구현 클래스에 대한 인터페이스를 정의하는
구현자(Implementor)
구현 클래스인 ConcreteImplementor
구조
역활
Abstraction의 역할
‘기능의 클래스 계층’의 최상위에 있는 클래스.
Implementor 역할의 메소드를 사용해서 기본적인 기능만 기술
되어 있는 클래스.
이 인스턴스는 Implementor 역할을 가지고 있다.
RefindedAbstraction의 역할
Abstraction 역할에다 기능을 추가한 역활.
Implementor의 역할
‘구현의 클래스 계층’의 최상위에 있는 클래스.
Abstractor 역할의 인터페이스(API)를 구현하기 위한 메소드를
규정하는 역할.
ConcreteImplementor의 역할
Implementor 역할의 인터페이스(API)를 구체적으로 구현하는
역할.
Adapter 패턴과 Bridge 패턴
하나의 클래스가 한 종류의 인터페이스를 다른 종
류의 인터페이스로 변환하기 위해 사용되었기 때
문에
Adapter패턴과 매우 닮았다고 생각하기 쉽다.
그러나 Adapter 패턴은
한 개 이상의 클래스 인터페이스를 특정 클래스의 인터페
이스와 동일하게 간주하기 위해 의도된 것이다.
이와 반대로 Bridge 패턴은
개발자가 클라이언트의 코드 내용을 변경하지 않고도
구현 내용을 바꾸거나 대체할 수 있도록
클래스의 인터페이스와 구현 내용을 분리시킨 것이다.
Example_DataList
데이터를 나타내는 리스트 방법에서 몇 가
지 변경사항이 필요하다 가정해보자.
예를 들어, 생산물의 목록을 알파벳 순으로
정렬하고자 할 수도 있다.
이렇게 하기 위해서는 상속된 클래스들의
수정을 필요하게 된다.
우리가 나타내야 할 것이 두 개 이상이 된다
면 더더욱 끔찍한 작업이 될 것이다.
Example_DataList
변경된 내용을 나타내기 위해 새로운 클래
스를 파생시키는 것보다는
Bridge를 만들어 작업하는 것이 더 나을 것
이다.
Example_Two steps
Example_Switch
Example_Window
Example_Seat
sample code in C#
Structural example
using System;
// Change implemention and call
namespace DoFactory.GangOfFour.Bri
ab.Implementor = new ConcreteImpl
dge.Structural
ementorB();
{
ab.Operation();
// MainApp test application
// Wait for user
class MainApp
Console.Read();
{
}
static void Main()
}
{
Abstraction ab = new RefinedAbstrac
tion();
// Set implementation and call
ab.Implementor = new ConcreteImpl
ementorA();
ab.Operation();
sample code in C#
Structural example
// "Abstraction"
class Abstraction
{
protected Implementor implementor;
// Property
public Implementor Implementor
{
set{ implementor = value; }
}
public virtual void Operation()
{
implementor.Operation();
}
}
// "Implementor"
abstract class Implementor
{
public abstract void Operation();
}
sample code in C#
Structural example
// "RefinedAbstraction"
class RefinedAbstraction : Abstraction
{
public override void Operation()
{
implementor.Operation();
}
}
sample code in C#
Structural example
// "ConcreteImplementorA"
class ConcreteImplementorA : Implementor
{
public override void Operation()
{ Console.WriteLine("ConcreteImplementorA Operation"); }
}
// "ConcreteImplementorB"
class ConcreteImplementorB : Implementor
{
public override void Operation()
{ Console.WriteLine("ConcreteImplementorB Operation"); }
}
}
sample code in C#
Structural example
sample code in C#
Real World example
using System;
// Exercise the bridge
using System.Collections;
customers.Show();
namespace DoFactory.GangOfFour.Brid
customers.Next();
ge.RealWorld
customers.Show();
{
customers.Next();
// MainApp test application
customers.Show();
class MainApp
{
customers.New("Henry Velasquez");
static void Main()
customers.ShowAll();
{
// Wait for user
// Create RefinedAbstraction
Console.Read();
Customers customers =
}
new Customers("Chicago");
}
// Set ConcreteImplementor
customers.Data = new CustomersData();
sample code in C#
Real World example
// "Abstraction"
class CustomersBase
{
private DataObject dataObject;
protected string group;
public CustomersBase(string group)
{
this.group = group;
}
sample code in C#
Real World example
// Property
public virtual void Show()
public DataObject Data
{ dataObject.ShowRecord(); }
{
public virtual void ShowAll()
set{ dataObject = value; }
{
get{ return dataObject; }
Console.WriteLine("Customer Group:
}
" + group);
public virtual void Next()
dataObject.ShowAllRecords();
{ dataObject.NextRecord(); }
}
public virtual void Prior()
}
{ dataObject.PriorRecord(); }
public virtual void New(string name)
{ dataObject.NewRecord(name); }
public virtual void Delete(string name)
{ dataObject.DeleteRecord(name); }
sample code in C#
Real World example
// "RefinedAbstraction"
--");
class Customers : CustomersBase
}
{
}
// Constructor
// "Implementor"
public Customers(string group) : base( abstract class DataObject
group)
{
{
public abstract void NextRecord();
}
public abstract void PriorRecord();
public override void ShowAll()
public abstract void NewRecord(string
{
name);
// Add separator lines
public abstract void DeleteRecord(strin
Console.WriteLine();
g name);
Console.WriteLine ("---------------------- public abstract void ShowRecord();
--");
public abstract void ShowAllRecords();
base.ShowAll();
}
Console.WriteLine ("----------------------
sample code in C#
Real World example
// "ConcreteImplementor"
class CustomersData : DataObject
{
private ArrayList customers = new Arr
ayList();
private int current = 0;
public CustomersData()
{
// Loaded from a database
customers.Add("Jim Jones");
customers.Add("Samual Jackson");
customers.Add("Allen Good");
customers.Add("Ann Stills");
customers.Add("Lisa Giolani");
}
public override void NextRecord()
{
if (current <= customers.Count - 1)
{
current++;
}
}
public override void PriorRecord()
{
if (current > 0)
{
current--;
}
}
sample code in C#
Real World example
public override void NewRecord(string public override void ShowAllRecords()
name)
{
{
foreach (string name in customers)
customers.Add(name);
{
}
Console.WriteLine(" " + name);
public override void DeleteRecord(stri }
ng name)
}
{
}
customers.Remove(name);
}
}
public override void ShowRecord()
{
Console.WriteLine(customers[curren
t]);
}
sample code in C#
Real World example
Example_Image
Example_Image
Example_Image
C# Implementation
// Structural Pattern:BRIDGE
using System;
//Base class for OS implemenations
interface ImageImp
{
void DoPaint(string str);
}
//Windows specific implemenation
class WinImp : ImageImp
{
public void DoPaint(string str)
{
Console.WriteLine(str + " WIN OS");
}
}
//Abstract class for all image paintings
class Image
{
public void SetImageImp(ImageImp ip)
{
impToUse = ip;
}
public virtual void Method(string s1)
{
}
protected ImageImp impToUse;
}
Example_Image
C# Implementation
//BMP specific paintings
class BMPImage : Image
{
override public void Method(string s1)
{
string s2 = s1 + " BMP IMAGE";
impToUse.DoPaint(s2);
}
}
//Client
class MyPaint
{
public Image SetUpMethod()
{
Image im = new BMPImage(); // BMP
IMAGE
ImageImp win = new WinImp();// WIN
OS
im.SetImageImp(win);
return im;
}
}
class MyMain
{
public static void Main()
{
MyPaint mp = new MyPaint();
Image im = mp.SetUpMethod();
im.Method("PAINTING-->");
}
}
장점
해당 인터페이스를 클라이언트의 프로그램에서 일정
하게 유지하기 위해 의도되는 패턴.
개발자가 출력하거나 사용하는 실제 클래스를 변경.
개발자가 사용자 인터페이스 모듈의 어려운 부분을
다시 컴파일해야 할 수고를 덜어줌.
Bridge 패턴 자체와 실제 최종 출력 클래스 부분만
다시 컴파일.
개발자는 클래스의 구현 내용과 Bridge클래스를 각각
별도로 상속할 수 있으며,
일반적으로 서로 지나치게 상호 작용할 필요가 없다.
클라이언트 프로그램으로부터 구현 내용을 훨씬 쉽게
감출 수 있다.
활용법 및 단점
추상과 구현이 한 클래스에 같이 붙어있지 않고 그
들을 분리하여 확장을 쉽게 하고 싶을 때 사용.
추상과 구현이 분리되어 결합도가 낮아진다.
추상은 그대로 두고 구현만 프로그램 실행중에 변
경해도 다른 클라이언트에게 영향을 미치지 않게
할 경우에 적용.
그 결과 추상과 구현을 서로 독립적으로 확장할수 있어
확장성이 개선.
여러 플랫폼에서 사용해야 할 그래픽스 및 윈도우
처리 시스템에서 유용.
인터페이스와 실제 구현부를 서로 다른 방식으로
변경해야 하는 경우 유용.
디자인이 복잡해진다는 단점.
적용영역
추상 클래스 혹은 인터페이스와 구현 클래스
사이의 항구적인 바인딩(permanent binding)을
피하고자 하는 경우
추상 클래스 혹은 인터페이스와 구현 클래스가
별도로 상속을 통해 확장되어야 하는 경우
구현 클래스에서의 변화가 클라이언트에 영향
을 미치지 않기를 원하는 경우
다수의 객체들이 하나의 구현 클래스를 공유하
면서 이러한 사실을 모르게 하고자 하는 경우
적용결과
인터페이스와 구현 사이의 결합도를 낮춘다
(decoupling).
추상 클래스 혹은 인터페이스와 구현 클래
스가 독립적인 계층 구조를 지니기 때문에
확장성이 개선된다.
클라이언트가 구현 클래스에 대한 세부 내
용을 알 수 없다.
관련패턴
Template Method
구현 클래스 계층을 이용. 상위 클래스에서는 추상
메소드를 사용해서 프로그래밍을 실행하고 하위 클
래스에서는 그 추상 메소드를 구현.
Abstract Factory
Bridge 패턴에 등장하는 ConcreteImplementor 역할
을 환경에 맞춰서 적절히 구축하기 위해 Abstract
Factory 패턴이 이용되는 경우도 있음.
Adapter
Bridge 패턴은 기능의 클래스 계층과 구현의 클래스
계층을 확실히 분리한 다음에 연결시키는 패턴.
Adapter 패턴도 기능은 비슷하지만 인터페이스(API)
가 다른 클래스를 결합시키는 패턴.
관련패턴 Example
(Example_GUI Component)
다른 패턴과의 비교
Adapter는 설계 후에 동작되고, Bridge는 설
계되기 이전에 작동한다. [GoF]
Bridge는 추상과 구현이 독립적으로 변하도
록 전면에 설계된다. Adapter는 관련없는 클
래스들이 함께 작동하도록 새롭게 개선한다.
[GoF]
인터페이스 클래스는 구현 클래스의 생성을
직접하지 않고 위임한다. 따라서, 구현객체
를 만드는 설계는 보통 Abstract Factory 패턴
을 사용한다. [Grand, Patterns in Java]
다른 패턴과의 비교
State와 Strategy, Bridge는 비슷한 해결 구조다.
차이는 다른 문제를 해결한다는 것이다.
[Coplien, Advanced C++]
State와 Bridge 구조는 동일하다. (Bridge는 계
층구조를 허용하지만, State는 하나만 허용한
다는 것만 제외). 이 두가지 패턴은 같은 구조를
사용해서 다른 문제를 해결한다. State는 객체
의 행동이 객체의 상태에 따라 바뀌도록 하지
만, 반면에 Bridge의 목적은 추상과 구현을 분
리하여 각각이 독립적으로 변화할 수 있도록
하는 것이다. [Coplien, C++ Report]
감사합니다
Q&A