대학생활/수업

게임인공지능 2주차 - Design Pattern, 전략 디자인 패턴, 옵저버 패턴, 데코레이터 패턴

se.jeon 2023. 9. 5. 13:07
728x90
반응형

Introduction to Design Pattern

우리가 해결하고자 하는 문제는 유일할 확률은 거의 없고, 대부분 복합적이다.

혼자서 고민하는 것보다는 듣고 찾아보는 것이 문제 해결에 도움이 될 때가 있다.

 

What is a Design Pattern?

- 대부분의 문제들은 누군가가 다양한 방법으로 이미 해결했을 가능성이 높다.

- 다양한 시도를 통해 해법들이 개선되면서 점차 구조화된 프로그래밍 방법으로 발전한다.

- 디자인 패턴은 완성된 코드가 아니다.

- 일반적이고 재사용 가능한 구조화된 프로그래밍 기법이다.

 

디자인 패턴이란

- 디자인 패턴은 누군가가 개발한 검증된 know-how이다.

- 라이브러리/프레임워크보다 상위 개념이다.

- 디자인 패턴을 적용하면 더 적은 노력으로 비슷한 문제의 해결이 가능하다.

 

하지만!

- 디자인 패턴은 그 자체로 해답이 되지 않는다.

- 각 상황에 맞는 변형이 필요하다.

- 그래서 경험을 통한 노하우 습득이 중요하다.

 

디자인 패턴의 장점

- 객체가 서로 느슨하게 결합되어 코드 변경이 쉽다. (Flexibility)

- 느슨한 결합과 응집도로 코드 재사용이 높다. (Reusability)

- 공통 어휘를 사용함으로써 코드 및 생각을 쉽게 공유할 수 있고, 팀 구성원간 이해를 높일 수 있다. (Shared vocabulary)

- 모범 사례를 통해 많은 것을 배울 수 있다. (Capture best practice)

디자인패턴 분류

생성 패턴 (Creational Pattern)

객체 생성 매커니즘을 다루는 디자인 패턴

- Factory Method

- Abstract Factory

- Builder

- Prototype (unity - prefab)

- Singleton

 

구조 패턴 (Structural Pattern)

클래스 및 객체를 조합/구성하여 더 큰 구조를 만드는 패턴

- Adapter

- Bridge

- Composite

- *Decorator

- Facade

- Proxy

 

행위 패턴 (Behavioral Pattern)

객체들 사이의 상호작용하는 방법 및 역할과 관련된 패턴

- Interpreter

- Template Method

- Command

- Iterator

- *Observer

- Strategy

- *State (FSM)

- Visitor

 

참고자료

Head First Design Patterns

What is a Stategy Design Pattern?

전략 디자인 패턴

프로그램 실행 중에 필요한 기능(알고리즘)을 선택할 수 있도록 하는 행위 패턴.

 

1. 사용할 기능 계열(알고리즘군)의 구조를 인터페이스(Interface)로 추상화 하여 정의한다.

2. 세부 기능들을 추상화된 인터페이스를 상속받아 캡슐화 한다.

3. 객체는 필요한 기능을 자유롭게 교체해가며 사용할 수 있도록 한다.

4. 새로운 기능이 필요하면 2의 방법으로 추가한다.

 

기존 코드의 변경 없이 새로운 전략을 추가할 수 있다.

 

 

Interface

인터페이스는 시스템 간 상호작용하기 위한 접점을 말한다.

객체지향프로그래밍에서는 함수로 상호작용한다.

인터페이스는 선언만 한다. (추상화)

실제 기능은 별도로 구현하여 위임한다. (델리게이션)

 

시나리오

- 여러가지 유형의 카메라가 있다.

- 카메라맨은 상황에 따라 적합한 카메라를 선택하여 촬영한다.

 

Camera1::void takePicture() >

                                                    iCameraInterface::virtual void takePicture() > Cameraman::iCameraInterface *myCam

                                                                                                                             setCamera(myCam), useCamera()

Camera2::void takePicture() >

실습 진행

#pragma once
class StrategeDesignedCameraman
{
};

class Cameraman
{
	iCameraInterface* myCam;

	void setCamera(iCameraInterface* cam);
	void useCamera();
};

__interface iCameraInterface
{
	virtual void takePicture();
};

class Camera1 : public iCameraInterface 
{
	void takePicture();
};

class Camera2 : public iCameraInterface
{
	void takePicture();
};

void Cameraman::setCamera(iCameraInterface* cam)
{
	myCam = cam;
}

void Cameraman::useCamera()
{
	myCam->takePicture();
}

전략 디자인 패턴 정리

1. 프로그램 실행 중에 필요한 기능(알고리즘)을 선택할 수 있도록 하는 행위 패턴이다.

2. 알고리즘군의 구조를 인터페이스로 추상화하여 정의하고

3. 세부 기능들은 추상화된 인터페이스를 상속받아 캡슐화하여

4. 객체가 필요한 기능을 자유롭게 교체해가며 사용할 수 있도록 하는 패턴.

5. 변하는 부분은 기능이며 필요할 때 마다 추가하여 적용한다.

6. 즉, 기존 코드의 변경 없이 새로운 전략을 추가할 수 있다.

Observer 패턴

'관측자', '관찰자', '감시자'

OS는 User의 이벤트를 감지/감시한다. (event listener)

 

옵저버 디자인 패턴

1. 정보 공급자의 상태가 바뀌면

2. 그 객체에 의존하는 구독자들에게 변경된 상태를 통지해서

3. 자동으로 옵저버들의 내용이 갱신되도록 하는 패턴

실습 진행

#pragma once
#include <iostream>
#include <list>
using namespace std;


__interface iObserber
{
	virtual void update(int num) = 0;
};

__interface iSubject
{
	virtual void registerObserver(iObserber* obs) = 0;
	virtual void removeObserver(iObserber* obs) = 0;
	virtual void notifyObservers() = 0;
};


class SubjectA : public iSubject
{
private:
	list<iObserber*> m_observers;
	int m_number;

public:
	SubjectA() : m_number(0) {};

	void setNumber(int num) 
	{
		m_number = num;
		notifyObservers();
	}
	void registerObserver(iObserber* obs) override
	{
		m_observers.push_back(obs);
	}
	void removeObserver(iObserber* obs) override
	{
		m_observers.remove(obs);
	}

	void notifyObservers() override 
	{
		list<iObserber*>::iterator iterPos;

		for (iterPos = m_observers.begin(); iterPos != m_observers.end(); iterPos++) 
		{
			iObserber* curPos = *iterPos;
			curPos->update(m_number);
		}
	}
};

class ObserverA : public iObserber 
{
public:
	ObserverA(iSubject* sub) 
	{
		sub->registerObserver(this);
	}

	void update(int num) override 
	{
		cout << "Observer A : " << num << endl;
	}
};

class ObserverB : public iObserber
{
public:
	ObserverB(iSubject* sub)
	{
		sub->registerObserver(this);
	}

	void update(int num) override
	{
		cout << "Observer B : " << num << endl;
	}
};


int main() 
{
	SubjectA* subject = new SubjectA();

	ObserverA* obsA = new ObserverA(subject);
	ObserverB* obsB = new ObserverB(subject);

	subject->setNumber(100);
}

옵저버 디자인 패턴 정리

1. 서로 상호작용하는 개체 사이에 느슨하게 결합(loosely coupled)하는 디자인 패턴이다.

2. subject 객체는 상태가 주기적으로 바뀐다.

3. subject에는 많은 observer 객체들이 등록된다.

4. subject와 observer는 one-to-many 관계이다.

5. subject에 등록된 observer 객체들은 subject의 변경된 상태/정보를 자동으로 받는다.

 

subject는 observer에 대해 몰라도 된다.

observer는 언제든 추가, 제거가 가능하다.

subject와 observer는 독립적으로 다른 곳에서 재사용 가능하다.

각각이 변경되어도 서로에게 영향을 주지 않는다.

데코레이터 디자인 패턴

기존 객체가 가지고 있는 기능에 새로운 기능을 동적으로 추가할 수 있는 패턴이다.

기존 코드 수정 없이 새로운 기능을 유연하게 확장 할 수 있다.

 

case 다양한 커피를 만드는 바리스타

1. DarkRoat 커피 객체를 생성

2. 커피에 Mocha 객체로 decorating

3. 커피에 Whip Cream 객체로 decorating

4. 비용을 계산

데코레이터 디자인 패턴 정리

기존 객체에 추가적인 기능을 동적으로 추가하는 패턴

Decorator는 서브클래스를 통해 기능을 유연하게 확장할 수 있는 방법이다.

기존 코드의 수정 없이 새로운 기능을 유연하게 확장할 수 있다.

728x90
반응형