66
Pattern C++ API 디자인 아꿈사 http:// cafe.naver.com/architect1 박진호 http:// blog.naver.com/jinojjan

Api design for c++ ch3 pattern

Embed Size (px)

Citation preview

Page 1: Api design for c++ ch3 pattern

PatternC++ API 디자인

아꿈사http://cafe.naver.com/architect1

박진호http://blog.naver.com/jinojjan

Page 2: Api design for c++ ch3 pattern

목차

Pimpl 이디엄 싱글톤과 팩토리 메서드 프록시 , 어댑터와 퍼사드 옵저버

Page 3: Api design for c++ ch3 pattern

Pimpl 이디엄

내부의 구체적인 코드를 public 헤더 파일로부터 완전히 숨김

기본적으로 private 멤버 변수와 함수를 .cpp 파일에 위치 시킴

Page 4: Api design for c++ ch3 pattern

Pimpl 이디엄공개 인터페이스Public: Function1() Function2()

Protected: Function3()

Private: Impl* pImpl 내부 구현

Public: PrivateFuntion1() PrivateFunction2() PrivateData1 privateData2

pImpl 이디엄은 숨겨진 구현 클래스를 내부 포인터로 가리키는 공개 클래스를 말함

Page 5: Api design for c++ ch3 pattern

Pimpl 사용 전// autotimer.h#ifdef WIN32#include <windows.h>#else#include <sys/time.h>#endif

#include <string>

class AutoTimer{public:  /// Create a new timer object with a human readable name  explicit AutoTimer(const std::string &name);  /// On destruction, the timer reports how long it was alive  AutoTimer();

private:  // Return how long the object has been alive  double GetElapsed() const;  std::string mName;#ifdef WIN32  DWORD mStartTime;#else  struct timeval mStartTime;#endif};

Page 6: Api design for c++ ch3 pattern

Pimpl 사용 후// autotimer.h#include <string>

class AutoTimer{public:  explicit AutoTimer(const std::string &name);  AutoTimer();

private:  class Impl;  Impl *mImpl;};

Page 7: Api design for c++ ch3 pattern

Pimpl 사용 후 Cpp 파일#include "autotimer.h"#include <iostream>#if_WIN32#include <windows.h>#else#include <sys/time.h>#endifclass AutoTimer::Impl{public:

  double GetElapsed() const  {#ifdef _WIN32    return (GetTickCount() - mStartTime) / 1e3;#else    struct timeval end_time;    gettimeofday(&end_time, NULL);    double t1 = mStartTime.tv_usec / 1e6 + mStartTime.tv_sec;    double t2 = end_time.tv_usec / 1e6 + end_time.tv_sec;    return t2-t1;#endif  }  std::string mName;#ifdef _WIN32  DWORD mStartTime;#else  struct timeval mStartTime;#endif};

Page 8: Api design for c++ ch3 pattern

Pimpl 사용 후 Cpp 파일

AutoTimer::AutoTimer(const std::string &name) : mImpl(new AutoTimer::Impl()){  mImpl->mName name;#ifdef _WIN32  mImpl->mStartTime = GetTickCount();#else  gettimeofday(&mImpl->mStartTime, NULL);#endif}

AutoTimer::AutoTimer(){  std::cout << mImpl >mName << ": took " << mImpl >GetElapsed() << " secs" << std::endl;  delete mImpl;  mImpl = NULL;}

Page 9: Api design for c++ ch3 pattern

Pimpl 사용 후 Cpp 파일

AutoTimer::AutoTimer(const std::string &name) : mImpl(new AutoTimer::Impl()){  mImpl->mName name;#ifdef _WIN32  mImpl->mStartTime = GetTickCount();#else  gettimeofday(&mImpl->mStartTime, NULL);#endif}

AutoTimer::AutoTimer(){  std::cout << mImpl >mName << ": took " << mImpl >GetElapsed() << " secs" << std::endl;  delete mImpl;  mImpl = NULL;}

Page 10: Api design for c++ ch3 pattern

Pimpl 설계 시 고려사항

1. Private 멤버 변수만을 포함한다 .

2. Private 멤버 변수와 함수를 포함한다 .

3. Public 클래스의 모든 함수와 대응되는 함수를 Impl 클래스에 구현한다 .

Page 11: Api design for c++ ch3 pattern

Pimpl 복사

기본적으로 얕은 복사가 사용됨 .

다음의 2 가지 선택사항을 취해 얕은 복사 시 예상치 못한 오류 발생 예방 클래스를 복사할 수 없게 만듦

▪ Private 으로 복사 생성자 선언 및 할당 연산자 선언 깊은 복사 기능을 명시적으로 정의

Page 12: Api design for c++ ch3 pattern

Pimpl 장점 정보 은닉

#define prive public #include “yourapi.h” #undef private

의존성 제거 Windows.h 및 sys/time.h 에 대한 의존성 없앰

빠른 컴파일 Api 계층 구조가 줄어듦

뛰어난 이진 호환성 Pimpl 이디엄 포함한 객체의 크기는 절대 바뀌지 않음

지연 할당 Pimpl 클래스는 필요할 때 생성되기 때문에 네트워크 연결과 같은

제한된 또는 많은 비용이 드는 리소스를 사용할 때 유용

Page 13: Api design for c++ ch3 pattern

Pimpl 단점 Pimpl 구현 객체를 메모리에 할당하고 해제해야하는 문제 .

포인터의 크기 때문에 객체 크기 역시 늘어나서 모든 변수 접근에 필요한 간접 참조의 성능 문제 발생

New 와 delete 호출에 따른 추가적인 비용▪ 빠른 Pimpl 이디엄 (new 와 delete 연산자를 오버로드 해서 적은 메모리를

사용하도록 고정된 크기의 메모리 할당자를 사용하는 효율적인 메모리 사용 방법 )

코드를 읽는 것 , 디버깅 하는것도 어려워 짐 .

상수 함수 안에 있는 변수들은 분리된 객체 안에 존재하기 때문에 컴파일러는 이 변수들의 값 변화를 더 이상 감지할 수없음 .

void PimpledObject::ConstMethod() const{  mImpl->mName = "string changed by a const method";}

Page 14: Api design for c++ ch3 pattern

C 에서의 Pimpl 구현

페이지 112 ~ 114 참고

Page 15: Api design for c++ ch3 pattern

싱글톤 구현 시 고려사항

어떻게 싱글톤 객체를 할당할 것인가 ?

언제 싱글톤 객체를 파괴 시킬 것인가 ?

쓰레드 안정성을 지원하는 가 ?

쭉정이 ( 알맹이가 없는 ) 싱글턴을 사용하면 어떻게 되는가 ?

Page 16: Api design for c++ ch3 pattern

싱글톤 이란 ?

발전된 형태의 전역 변수

프로그램 상에서 하나의 인스턴스만 있고 두번째 인스턴스를 만들 수 없는 기능

쓰임에 따라 최선의 방법들이 달라짐

Page 17: Api design for c++ ch3 pattern

싱글톤 기본 지원 사항 –단일 객체 보장

기본 생성자를 private 에 선언 외부에서 new로 객체 생성 불가 Singleton* pObject = new Singleton(); 컴파일 에러

복사 생성자 , 복사 대입연산자 도 private 에 선언 복사로 인한 생성 불가 정의를 하지 않고 선언만 함

(정의가 있으면 멤버함수 혹은 프렌드 함수가 호출 할 수 있기 때문에 정의 하지 않음 )

복사 생성자▪ Singleton object1( Singleton::GetInstance() ); 컴파일 에러

복사 대입 연산자▪ Singleton& object1 = Singleton::GetInstance();▪ Singleton& object2 = Singleton::GetInstance();▪ object1 = object2; 컴파일 에러

Page 18: Api design for c++ ch3 pattern

첫번째 싱글톤

.h

.cpp

Page 19: Api design for c++ ch3 pattern

첫번째 싱글톤 고찰 Static 클래스 멤버 변수는 static 전역 변수처럼 프로그램

시작 시 main() 함수 호출 이전에 초기화

싱글톤 객체 사용하지 않더라도 무조건 생성되기 때문에 비효율적

정적 객체는 다른 전역객체의 생성자에서 참고하고 싶은 경우 문제 발생 할 수 있음 C++ 표준에서는 전역 객체들의 생성 순서에 대해 명확하게

정의하고 있지 않기 때문 Main() 함수가 실행 하기 전에만 생성되면 됨 어떤 전역 객체의 생성자에서 위 싱글톤 객체를 참조하려고 할 경우

싱글톤 객체가 생성되기 전인 경우 문제 발생 할 수 있음

Page 20: Api design for c++ ch3 pattern

두번째 싱글톤

.h

.cpp

Page 21: Api design for c++ ch3 pattern

두번째 싱글톤 고찰

최초 GetInstace() 를 호출하는 시점에 객체가 생성

한번도 해당 객체를 생성하지 않으면 객체 생성 하지 않으므로 자원을 효율적으로 사용

다른 전역 객체의 생성자에서 참조하는 것도 가능

프로그램이 종료되는 순간 동적 객체는 자동으로 해제되기 때문에 굳이 명시적으로 해제할 필요 없음

Page 22: Api design for c++ ch3 pattern

exit(0) 의 내부 동작 프로그램을 종료하기 위해 exit() 가 수행하는 cleanup 과정 (C++ 기준 )

1. 현재 thread의 thread storage duration 내에 있는 object 들을 모두 소멸 ( C++11 only)

2. static storage duration의 object들을 소멸1. Static storage duration2. Thread storage duration3. Automatic storage duration4. Dynamic storage duration

3. atexit 에 등록되어 있는 함수들을 호출

4. 모든 C stream(stdin, stdout, stderr 등등 ) 과 tmpfile 에 의해 생성된 파일들을 비우고 닫음

5. 제어권이 host environment 로 넘어감

Page 23: Api design for c++ ch3 pattern

세번째 싱글톤 – 명시적 해제

두번째 싱글톤 객체가 반드시 프로그램 종료 시 반납해야 하는 외부 시스템 자원을 사용하는 경우 사용 싱글턴 객체를 이용하여 , OS 리소스 를 만들고 해제 하지

않는다면 " 리소스 릭 :Resource Leak" 이 발생 싱글턴 객체의 소멸자에 리소스 해제 기능을 놓고 , 싱글턴

객체를 파괴 함 으로써 이러한 문제 해결

Ateexit() 함수를 사용

다른 전역 객체의 소멸자를 이용

Page 24: Api design for c++ ch3 pattern

Atexit()

#include <stdlib.h> int atexit(void (*func)(void));

함수 호출 성공 시 0, 실패 시 0 아닌 값 반환 .

반환형과 매개변수 형이 void 로 선언된 함수의 이름이 ( 주소 값이 ) atexit함수의 인자로 전달

인자로 전달된 함수가 프로그램 종료 시 자동으로 호출되며 , 이렇게 자동으로 호출되어야 할 함수는 32개 이상 등록할 수 있음 .

atexit 함수의 특성 등록된 순서의 역순으로 호출 atexit 함수를 통해서 등록된 함수는 프로그램이 정상적으로 종료될 때에만 호출

Page 25: Api design for c++ ch3 pattern

세번째 싱글톤 – 명시적 해제 atexit() .h

.cpp

Page 26: Api design for c++ ch3 pattern

세번째 싱글톤 – 명시적 해제 전역 객체의 소멸자 이용 .h

.cpp

Page 27: Api design for c++ ch3 pattern

네번째 싱글톤 – static 지역 객체

명시적 해제 작업을 피하기 위해 static 지역 객체 사용

1. 지역 static 객체는 전역 static 객체와 달리 해당 함수를 처음 호출 하는 시점에 초기화2. 위 객체를 한번도 사용하지 않으면 생성되지 않음3. Static 이므로 프로그램 종료 시 까지 객체가 유지4. 종료시에는 자동으로 소멸자 호출

Page 28: Api design for c++ ch3 pattern

네번째 싱글톤 고찰 로그 객체 , 키보드 객체 , 모니터 객체가 존재하며 , 네번째 싱글톤으로 구성

(1)키보드 객체를 생성하고 , 모니터 객체를 생성 하는 중 실패하여 , (2)로그 객체를 생성하여 로그를 찍음 (3)그리고 프로그램이 종료 작업에 들어 가게 됨 .

에러 상황 (4) 로그 객체는 먼저 삭제됨 . (5)키보드 객체를 파괴할 때 , 실패하여 , (6)로그 객체를 이용해 로그를 찍으려 함 하지만 , 로그 객체는 이미 파괴된 후이므로 , 쭉정이 싱글톤에 접근하게 되어 , 크래쉬가 발생

상황 분석 static 을 이용하기 때문에 , 스택 형태로 메모리에 올라와져 있어 , 키보드 객체가 파괴되기 전 로그 객체

부터 파괴 . 왜냐하면 로그 객체가 키보드 객체 후에 만들어졌기 때문

Page 29: Api design for c++ ch3 pattern

네번째 싱글톤 고찰

네번째 싱글톤 객체를 다른 전역 객체의 소멸자에서 사용하려고 하면 문제 발생 C++ 표준에서는 전역 객체들의 생성 순서만

명시하지 않은 것이 아니라 소멸 순서에 대해서도 명시해놓지 않음

어떤 전역 객체가 소멸자에서 저 싱글톤 객체를 사용하려고 할 때 싱글톤 객체가 먼저 소멸했다면 문제가 발생 ( 참조 무효화 )

Page 30: Api design for c++ ch3 pattern

다섯번째 싱글톤 – 피닉스 싱글톤

싱글톤 참조 시 해당 객체의 소멸 여부를 파악하고 만약 소멸했다면 되살림

싱글턴의 파괴 시점을 조작

Page 31: Api design for c++ ch3 pattern

다섯번째 싱글톤 – 피닉스 싱글톤

Static 지역 변수의 특징 메모리의 생성은 프로그램이 static 지역변수 가 포함된

함수를 호출해야 생성 프로그램 종료 시점에 메모리 파괴가 일어난다 해도 그

공간은 빈 공간으로 남아 있음 ( 다른것으로 채워지지 않음 )

위 특징 사용 . 프로그램 종료 시점에 그 메모리 공간에 다시 쓰기 위해

replacement new 를 사용 파괴 시점을 제어하기 위해 std::atexit 함수 사용

Page 32: Api design for c++ ch3 pattern

다섯번째 싱글톤 – replacement new

Replacement new 이미 할당된 메모리 공간에 생성자만 호출 일반 new 처럼 사용하되 인자로 메모리가 할당되어있는 포인터를 넘겨줌 내부적으로 void* operator new(size_t, void*) 원형의 new 를

호출 Ex) void* pBase = malloc(sizeof(CBase)); new(pBase) CBase;

메모리를 재할당 하지 않음 기존 데이터가 그대로 남아있고 , 생성자에서 초기화하는 데이터만 초기화 가상함수 테이블을 초기화 메모리풀링 등에서 유용하게 사용

Page 33: Api design for c++ ch3 pattern

다섯번째 싱글톤 – 피닉스 싱글톤

.h

Page 34: Api design for c++ ch3 pattern

다섯번째 싱글톤 – 피닉스 싱글톤

.cpp

Static 객체의 생성 / 소멸 시점에 대해 정확히 파악해서 싱글톤 객체를 전역 객체의 생성 / 소멸자에서 마구잡이로 참조하는 일이 없도록 주의해서 프로그래밍 해야함

Page 35: Api design for c++ ch3 pattern

싱글톤이 쓰레드를 만났을 때

고려해야 할 사항 싱글턴 객체의 생성 동기화

Page 36: Api design for c++ ch3 pattern

싱글톤이 쓰레드를 만났을 때

고려해야 할 사항 싱글턴 객체의 생성 동기화

Page 37: Api design for c++ ch3 pattern

싱글톤이 쓰레드를 만났을 때

멀티 스레드 환경 지원 안함

Page 38: Api design for c++ ch3 pattern

싱글톤이 쓰레드를 만났을 때

쓰레드 A가 GetInstance() 함수 진입

1번 조건 체크 하고 다음 줄 실행 전에 중지

쓰레드 B가 GetInstance() 함수에 진입

쓰레드 B는 s_pInstance가 NULL 이므로 1번 계속 진행 . 쓰레드 B는 2번 실행하여 객체 생성 후 호출자에게 instance 리턴

쓰레드 A는 다시 진행 됨 . 2번이 다시 호출되어 또다른 인스턴스 생성

A 쓰레드 B 쓰레드2 번

1 번2 번

1 번

Page 39: Api design for c++ ch3 pattern

쓰레드를 만났을 때 - Lock

B 쓰레드

Page 40: Api design for c++ ch3 pattern

쓰레드를 만났을 때Double checked Locking Pattern

널일 경우에만 락을 획득 하기 위함

위 조건 체크와 락을 얻을 때 사이에 다른 스레드가 먼저 들어와서 pInstance 를 초기화 할 수 있기 때문에 한번더 null 인지 체크

Page 41: Api design for c++ ch3 pattern

쓰레드를 만났을 때Double checked Locking Pattern

s_pInstance = new LazySingleton(); 의미 1. Singleton 객체를 담기 위한 메모리를 할당 2. 할당된 메모리에 Singleton 객체를 생성 3. s_pInstance 가 할당된 메모리를 가리키도록

컴파일러가 이 순서대로 수행되도록 제한하지 않음 . 컴파일러는 때때로 스텝 2 와 스텝 3 사이의 순서를 바꾸기도 함

Page 42: Api design for c++ ch3 pattern

쓰레드를 만났을 때Double checked Locking Pattern

A 쓰레드에서 s_pInstance 가 할당된 메모리를 가리키도록 하고 그 후에 할당된 메모리에 객체를 생성 해야 하는데 할당 전에

B 쓰레드에서 싱글턴 객체를 바로 사용할 경우 껍데기를 접근하여 문제 발생

( 싱글턴 객체는 메모리를 가리키기만 하고 실제 객체객체 생성은 안된 상황 )

Page 43: Api design for c++ ch3 pattern

쓰레드를 만났을 때Double checked Locking Pattern

Volatile 한정 지시자 사용

Page 44: Api design for c++ ch3 pattern

Volatile 의미

volatile 로 선언된 개체 ( 변수 , 메모리 위치 , 코드 ) 는 op-timize 룰을 적용하지 말라 . ( Objects declared as volatile are not used in certain op-

timizations ( 출처 - MSDN ))

컴파일러가 효율 등을 고려해 optimize 관점에서 코드를 임의로 변경 ( 의미 없는 코드 삭제나 실행 순서 변경 ) 을 시키지 않음

volatile 로 선언된 개체는 메모리에 할당되고 작업 요청시 직접 ( 해당 주소에 ), 바로 ( 효율을 위한 지연 없이 ) 처리된다 .

Page 45: Api design for c++ ch3 pattern

Volatile

volatile 키워드를 사용해야 할 곳이 있다면 C++11에서는 atomic 변수를 사용

C++11 에서는 ' 서로 다른 스레드 간에 순서 관계가 정의 되지 않은 메모리 읽기 쓰기 조작은 data race 에 의한 알 수 없는 동작을 한다 ' 라고 되어 있음 .

즉 C++11 에서 volatile 변수는 Memory Barrier 동작을 한다고 명시하지 않음

메모리 바리어는 대부분 낮은 수준의 기계어에서 사용되며 여러 장치가 공유하는 메모리를 사용하는 데 쓰임

Page 46: Api design for c++ ch3 pattern

atomic

Page 47: Api design for c++ ch3 pattern

스레드에 안전하게 만든게 성능에 문제 될 시 Lazy Instance 모델 대신 코드가 실행되는 시

점 , main() 이 호출되기 전이나 뮤텍스 잠금으로 API 가 초기화 시점에 초기화

정적 초기화 static Singleton& foo = Singleton::GetInstance();

명시적 API 초기화Void APIInitialize(){ Mutex mutex; ScopredLock(&mutex); Singleton::GetInstance();}

Page 48: Api design for c++ ch3 pattern

싱글톤 대체 방법 의존성 삽입

class MyClass{public: MyClass() : mDatabase( new Database ("mydb, "localhost", "user", "pass")) {}private: Database* mDatabase;}

class MyClass{public: MyClass(Database* db) : mDatabase(db) {}private: Database* mDatabase;}

Page 49: Api design for c++ ch3 pattern

싱글톤 대체 방법 모노스테이트 패턴

싱글톤의 문제는 전역 상태를 유지하고 접근하는데서 발생// monostate.hclass MonoState{public:

int GetTheAnswer() const { return sAnswer; }private:

static int sAnswer;};

// monostate.cppint MonoState::sAnswer = 42;

세션 문맥 사용

Page 50: Api design for c++ ch3 pattern

Factory Method 패턴

C++ 생성자에서의 제약 사항 결과 값 리턴 불가 명명 규칙의 제약 정적 형식의 객체 생성 가상 생성자의 부재

팩토리 메서드는 위 제약사항에 구애받지 않음

Page 51: Api design for c++ ch3 pattern

SimpleFactory

// renderer.h#include <string>class IRenderer{public:  virtual IRenderer() {}  virtual bool LoadScene(const std::string &filename) 0;  virtual void SetViewportSize(int w, int h) 0;  virtual void SetCameraPosition(double x, double y, double z) 0;  virtual void SetLookAt(double x, double y, double z) 0;  virtual void Render() 0;};

Page 52: Api design for c++ ch3 pattern

SimpleFactory

// rendererfactory.h#include "renderer.h"#include <string>class RendererFactory{public:  IRenderer *CreateRenderer(const std::string &type);};

// rendererfactory.cpp#include "rendererfactory.h"#include "openglrenderer.h"#include "directxrenderer.h"#include "mesarenderer.h“

IRenderer *RendererFactory::CreateRenderer(const std::string &type){  if (type "opengl")    return new OpenGLRenderer();

  if (type "directx")    return new DirectXRenderer();

  if (type "mesa")    return new MesaRenderer();

  return NULL;}

Page 53: Api design for c++ ch3 pattern

Factory Method 패턴

사용자가 원하는 타입의 인스턴스를 런타임시에 생성하기 때문에 유연성 제공

상속 클래스의 헤더 파일은 팩토리를 구현하는 .cpp 파일에만 존재하며 public 으로 선언된 RenererFacory.h 파일에는 포함하지 않음

그러나 이것은 사용자에게 새로운 그래픽 처리기를 제공하지 못함 .

Page 54: Api design for c++ ch3 pattern

확장 가능한 Factory Method

팩토리 메서드와 상속 클래스간의 연결 관계를 느슨하게 만듦

런타임시에 새로운 상속 클래스를 추가할 수 있도록 타입 이름을 객체 생성 콜백 함수에 연결시키는 맵을 팩토리 클래스에서 사용

Page 55: Api design for c++ ch3 pattern

확장 가능한 Factory Method

// rendererfactory.h#include "renderer.h"#include <string>#include <map>class RendererFactory{public:  typedef IRenderer *(*CreateCallback)();  static void RegisterRenderer(const std::string &type, Create-Callback cb);  static void UnregisterRenderer(const std::string &type);  static IRenderer *CreateRenderer(const std::string &type);

private:  typedef std::map<std::string, CreateCallback> CallbackMap;  static CallbackMap mRenderers;};

Page 56: Api design for c++ ch3 pattern

확장 가능한 Factory Method

#include "rendererfactory.h"// instantiate the static variable in RendererFactoryRendererFactory::CallbackMap RendererFactory::mRenderers;

void RendererFactory::RegisterRenderer(const std::string &type, CreateCallback cb){  mRenderers[type] cb;}

void RendererFactory::UnregisterRenderer(const std::string &type){  mRenderers.erase(type);}

IRenderer *RendererFactory::CreateRenderer(const std::string &type){  CallbackMap::iterator it mRenderers.find(type);  if (it ! mRenderers.end())  {    // call the creation callback to construct this derived type    return (it >second)();  }  return NULL;}

Page 57: Api design for c++ ch3 pattern

확장 가능한 Factory Method

class UserRenderer : public IRenderer{public:  UserRenderer() {}  bool LoadScene(const std::string &filename) { return true; }  void SetViewportSize(int w, int h) {}  void SetCameraPosition(double x, double y, double z) {}  void SetLookAt(double x, double y, double z) {}  void Render() { std::cout << "User Render" << std::endl; }  static IRenderer *Create() { return new UserRenderer(); }};

int main(int, char **){  // register a new renderer  RendererFactory::RegisterRenderer("user", UserRenderer::Create);  // create an instance of our new renderer  IRenderer *r RendererFactory::CreateRenderer("user");  r->Render();  delete r;  return 0;}

Page 58: Api design for c++ ch3 pattern

API Wrapping 패턴 - 어댑터 패턴

한 클래스의 인터페이스를 클라이언트에서 사용하고자 하는 다른 인터페이스로 변환 어댑터를 이용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있음 .

Page 59: Api design for c++ ch3 pattern

API Wrapping 패턴 - 어댑터 패턴

public class Adapter implements target{ request(){ translatedRequest(); }}

클라이언트와 어댑티는 서로 분리서로 상대방에 대해서 전혀 모름 .

Page 60: Api design for c++ ch3 pattern

API Wrapping 패턴 - 어댑터 패턴

어댑터에서 타겟 인터페이스를 구현

어댑터는 어댑티로 구성

모든 요청은 어댑티에게 위임

public class Adapter implements tar-get{ request(){ specificRequest(); }}

객체 구성 (Composition) 사용

어댑티의 어떤 서브클래스에 대해서도 어댑터를 쓸 수 있다는 장점

클라이언트를 특정 구현이 아닌 인터페이스에 연결

- 여러 어댑터 사용 가능- 타겟 인터페이스만 제대로 지키다면 다른 구현 추가

가능

Page 61: Api design for c++ ch3 pattern

API Wrapping 패턴 - 어댑터 패턴

다중상속을 사용해서 어댑터를 어댑티와 타켓 클랙스 모두의 서브클래스로 만듦 .

※ 자바에서는 실제로 동작하지 않는 코드입니다public class Adapter extends Target, Adaptee{ public void request(){ specificRequest(); }}

Page 62: Api design for c++ ch3 pattern

API Wrapping 패턴 – 어댑터 패턴

- 어댑티 전체는 다시 구현하지 않아도 됨- 어댑티의 행동을 오버라이딩 가능

- 구성을 사용하기 때문에 그 서브클래스에 대해서도 어댑터 역할을 할 수 있음

Page 63: Api design for c++ ch3 pattern

API Wrapping 패턴 - 퍼사드 패턴 어떤 서브시스템의 일련의 인터페이스에 대한 통합된 인터페이스를 제공

퍼사드에서 고수준 인터페이스를 정의하기 때문에 서브시스템을 더 쉽게 사용할 수 있음

Page 64: Api design for c++ ch3 pattern

API Wrapping 패턴 – 옵저버 패턴클래스 다이어그램

1. 일대다 관계 (one-to-many)

• 상태를 저장하고 지배하는 것은 주제 객체 .

• 옵저버는 여러 개가 있을 수 있지만 ,

주제 객체에서 상태가 바뀌었다는 것을 알려주기를

기다리는 주제에 의존 적인 성질을 가짐 .

2. 의존성

1. 옵저버는 주제 객체가 데이터를 갱신해 주기를

기다리는 입장 이기 때문에 의존성을 가짐 .

2. 이런 방식으로 인해

깔끔한 객체지향 디자인을 만들 수 있음 .

update()

<interface>

Observer

regosterObserver() { … }removeObserver() { … }notifyObservers() { … }

getState( )setState( )

ConcreateSubject

regosterOb-server()removeObserver()notifyObservers()

<interface>Subject

update()

// 기타 해당 옵저버의 메소드

ConcreateObserver

옵저버

주제

옵저버가 될 가능성이 있는 객체는 해당 인터페이스 상속 .

옵저버를 등록 / 탈퇴 / 공지

하는 기능

상태를 설정하는 메소드가 필요

• 옵저버 패턴

한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들한테 연락이 가고 자동으로 내용이 갱신되는 방식으로 일대다 (one-to-many) 의존성을 정의

Page 65: Api design for c++ ch3 pattern

API Wrapping 패턴 - 옵저버 패턴 옵저버 패턴에서는 주제와 옵저버가 느슨하게 결합되어 있는 객체

디자인을 제공 .

주제가 옵저버에 대해 아는 것은 옵저버가 특정 인터페이스를 구현(implements) 한다는 것 뿐 .

옵저버는 언제든지 새로 추가할 수 있음

새로운 형식의 옵저버를 추가하려고 할 때도 주제를 전혀 변경할 필요가 없음 .

주제와 옵저버는 서로 독립적으로 재사용할 수 있음 .

주제나 옵저버가 바뀌더라도 서로한테 영향을 미치지 않음 .

Page 66: Api design for c++ ch3 pattern

감사합니다