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