(book summary)GoF Design Pattern

simuruk wiki

  • 저자 Gang of Four






디자인 패턴이란

  • 때에 따라 때려 맞추는 ad hoc(특별한 목적을 위해서라는 라틴어)해결책보다 좀더 수고를 해여 유연성과 재사용성을 얻을수 있다
  • 설계자들이 이미 경험한 소프트웨어 설계의 경험을 기록 해놓아 설계를 그대로 적용(재사용)할수 있다
  • 특정한 전후 관계에서 일반적 설계 문제를 해결하기 위해 상호교류하는 수정 가능한 객체와 클래스들에 대한 설명입니다
  • 구체적인 설계나 구현을 설명하지 않고 추상화를 갖는 패턴까지 설명합니다

디자인 패턴 4가지 요소

  • Pattern name 패턴이름은 한두 단어로 설계 문제와 해법을 서술해야한다
  • Problem 문제는 언제 패턴을 사용하는지 해결할 문제와 그 배경을 설명합니다
  • Solution 해법은 설계를 구성하는 요소들과 그 요소들 간의 관계, 책임 그리고 협력 관계를 서술합니다
  • Consequence 결과는 디자인 패턴을 적용해서 얻는 결과와 장단점을 서술합니다
    • 비용과 효과를 측정하여 디자인패턴을 선택하기 때문에 가장 중요한 부분입니다
    • 재사용성도 중요한 요소로 시스템의 유연성, 확장성, 이식성등에 커다란 영향을 줍니다






사례







Creational(생성)

  • 추상 팩토리
  • 빌더
  • 팩토리 메서드
  • 프로토타입

싱글턴

멀티스레드 개발에서 일관성을 보장해주는 방식

  • 생성자 막기
  • 소멸자 막기
  • getter
  • multithread
// C++
Foo* Foo::Instance() {
  if(pinstance == nullptr) {
    lock_guard<mutex> lock(m_);
    if(pinstance == nullptr) {
        pinstance = new Foo();
    }
  }
  return pinstance;
}
// JAVA
public static synchronized singleton getInstance () {
    if (instance == null)
        instance = new ThreadSafeInitalization();
    return instance;
}

접기 1. 주소 값을 이용한 방식

 
class yh_singleton
{
public:
	static yh_singleton&amp; getInstanse(){
		static yh_singleton instance;
		return instance;
	};
	int num;
private:
	yh_singleton(){};
	yh_singleton(const yh_singleton&amp; other);
	yh_singleton&amp; operator=(yh_singleton&amp; cls);
	~yh_singleton(){};
};

yh_singleton&amp; yh= yh_singleton::getInstanse();
yh.num= 4;

2. 포인터를 이용한 방식

 
class yh_singleton
{
public:
	static yh_singleton* getInstanse(){
		static yh_singleton instance;
		return &amp;instance;
	};
	int num;
private:
	yh_singleton(){};
	yh_singleton(const yh_singleton&amp; other);
	yh_singleton&amp; operator=(yh_singleton&amp; cls);
	~yh_singleton(){};
};

yh_singleton* yh= yh_singleton::getInstanse();
yh->;num= 4;

3. 템플릿 싱글톤

 
template &lt;typename T&gt;
class yh_singleton
{
public:
	static T* getInstance()
	{
		if (instance == NULL)
			instance = new T;
		return instance;
	};

	static void destroyInstance()
	{
		if (instance)
		{
			delete instance;
			instance = NULL;
		}
	};
private:
	static T* instance;
protected:
	yh_singleton(const yh_singleton&amp; other);
	yh_singleton&amp; operator=(yh_singleton&amp; cls);
	yh_singleton();
	virtual ~yh_singleton(){};
};
template &lt;typename T&gt;T * yh_singleton&lt;T&gt;::instance = NULL;

class ojectA : public yh_singleton&lt;ojectA&gt;
{
public:
	ojectA();
	~ojectA();

	int a;
};






Structural(구조)

  • 어뎁터
  • 브릿지
  • 컴포지트
  • 데코레이터
  • 퍼사드
  • 플라이 웨이트
  • 프록시






Behavioral(행동)

  • 체인 오브 리스판시빌리티
  • 코맨드
  • 인터프리터
  • 이터레이터
  • 메디에이터
  • 메멘토
  • 옵저버
  • 스테이트

스트레티지

참고

  • is-a보다 has-a가 좋을수 있다
  • 상속 보다는 구성을 활용한다

의도

  • 동일 계열 알고리즘군을 정의하고 각각을 캡슐화하여 상호 교환해서 사용할 수 있도록 합니다
  • 알고리즘을 사용하는 클라이언트와 상관없이 독립적으로 알고리즘을 변경할 수 있게 합니다

동기

  • 알고리즘 코드가 분리가 되어있지 않다면 클래스가 복잡해진다
  • 때에 따라서 알고리즘이 다르기 때문에 변경이 어렵다
  • 새로운 알고리즘을 추가하거나 기존의 것을 다양화하기가 어렵다
  • 이런 캡슐화된 알고리즘을 전략이라고 합니다

활용성

  • 많은 행동중 하나를 가진 클래스를 구성할 수 있는 방법을 제공합니다
  • 알고리즘의 변형이 필요할때 변경할수 있습니다
  • 사용자가 몰라야 하는 알고리즘이 있을때 전략 클래스에만 두면 되므로 사용자가 몰라도 됩니다
  • 하나의 클래스가 많은 행동을 정의하고, 이런 행동이 다중 조건문의 모습을 취할때 각각을 전략 클래스로 옭겨놓는 것이 좋습니다

참여자

  • 스트레티지(컴포지터): 알고리즘 인터페이스
  • 컨크리트 스트레티지: 실제 알고리즘
  • 컨택스트(컴포지션): 전락에 대한 참조자 관리, 스트레티지의 서브클래스 인스턴스를 갖고 있음으로 구체화합니다

결과

  • 동일 계열의 관련 알고리즘군이 생깁니다, 재사용도 가능합니다
  • 서브클래싱을 사용하지 않는 대안입니다, 알고리즘을 변형, 이해, 확장이 쉽습니다
  • 조건문을 없앨 수 있습니다
  • 구현의 선택이 가능합니다, 전략중 하나를 선택하여 사용합니다
  • 사용자(프로그램)는 서로 다른 전략을 알아야 합니다
  • 전략 객체와 컴포지션 객체 사이에 의사소통 오버헤드가 있습니다, 사용되지 않는 매개변수를 컴포지션이 떠안아야합니다
  • 객체 수가 증가합니다, 플라이웨이트를 사용하면 좋습니다
  • 템플릿 메서드
  • 비지터

디자인 패턴기대

다이어그램