Observer 예시 (인터페이스 정의)
#pragma once
/*=================================
Observer Pattern
=================================*/
/*
객체의 상태 변화에 따라 다른 객체가 자동으로 업데이트되는 디자인 패턴으로
이벤트 시스템이나 데이터 변경 통지 시스템에서 사용 된다.
장점
ㄴ 느슨한 결합 : 옵저버 관리 객체와 옵저버 간의 결합도가 낮아 서로의 구현에 의존하지 않고 독립적으로 개발 가능
ㄴ 유연성 : 새로운 옵저버를 추가하거나 기존 옵저버를 제거하는 것이 용이하며 시스템의 변경이 비교적 쉽다.
ㄴ 재사용성 : 다양한 옵저버 관리 객체와 옵저버 조합을 재사용하기가 쉽다.
단점
ㄴ 복잡성 : 옵저버가 많을 수록 여러 옵저버에 대한 상태를 관리해야 하므로 복잡해질 수 있다.
ㄴ 메모리 누수 : 옵저버가 관리 객체에 등록된 후 관리 객체가 사라질 경우 옵저버가 여전히 참조를 유지할 가능성이 있다.
*/
enum class EEventType
{
// 날씨 관련 이벤트
DAY,
NIGHT,
RAINY,
SNOWY,
// 다른 이벤트 추가
};
// 옵저버 인터페이스
class IObserver
{
public:
virtual ~IObserver() {}
public:
virtual void update(EEventType event) = 0;
};
// 관리 대상 인터페이스
class ISubject
{
public:
virtual ~ISubject() {}
public:
virtual void attach(IObserver* observer) = 0; // 옵저버 등록
virtual void detach() = 0; // 옵저버 해제
virtual void notify(EEventType event) = 0; // 이벤트 통지
};
관리 클래스 생성 (Weather)
#pragma once
#include "Observer.h"
class WeatherSubject : public ISubject
{
public:
WeatherSubject() {}
~WeatherSubject() {}
public:
void attach(IObserver* observer) override
{
_observers.push_back(move(observer));
}
void setWeather(EEventType event)
{
notify(event);
}
private:
void detach() override
{
_observers.clear();
}
void notify(EEventType event) override
{
for (IObserver* observer : _observers)
{
observer->update(event);
}
detach();
}
private:
vector<IObserver*> _observers;
};
Observer 인터페이스 상속
ㄴ Prototype Pattern에서 만든 Character 클래스 재사용
https://mygameprogramming.tistory.com/338
Prototype Pattern
Prototype 예시 (Character)#pragma once/*================================= Prototype Pattern=================================*//*프로토 타입 패턴은 객체 생성 방식 중 하나로 기존의 객체를 복제하여 새로운 객체를 만드는
mygameprogramming.tistory.com
/*
Observer Pattern을 위한 IObserver 상속 추가
*/
#include "Observer.h"
class Character : public IObserver
{
public:
virtual ~Character() {}
protected:
Character() {}
Character(int hp, int mp, int speed, string name)
: _hp(hp), _mp(mp), _speed(speed), _name(name)
{}
public:
int getHP() const
{
return _hp;
}
int getMP() const
{
return _mp;
}
int getSpeed() const
{
return _speed;
}
string getName() const
{
return _name;
}
void setHP(int health)
{
_hp = health;
}
void setMP(int magic)
{
_mp = magic;
}
void setSpeed(int spd)
{
_speed = spd;
}
void setName(const string& name)
{
_name = name;
}
public:
virtual unique_ptr<Character> clone() const = 0;
virtual void display() const = 0;
virtual void attack() = 0;
public:
void update(EEventType event) override
{
switch (event)
{
case EEventType::DAY:
dayUpdate();
break;
case EEventType::NIGHT:
nightUpdate();
break;
}
}
private:
void dayUpdate()
{
_speed += 5;
if (_speed > 100)
{
_speed = 100;
}
cout << _name << " " << "현재 이동 속도 : " << _speed << " " << "낮일 때 이동속도 증가\n";
}
void nightUpdate()
{
_speed -= 10;
if (_speed < 0)
{
_speed = 0;
}
cout << _name << " " << "현재 이동 속도 : " << _speed << " " << "밤일 때 이동속도 감소\n";
}
private:
string _name;
int _hp = 0;
int _mp = 0;
int _speed = 0;
};
Observer 사용
enum Hour
{
DAY,
NIGHT
};
// 임시 시간 구하기
int getHour()
{
auto now = chrono::system_clock::now();
time_t now_c = chrono::system_clock::to_time_t(now);
tm localTime;
localtime_s(&localTime, &now_c);
int hour = localTime.tm_hour;
if (hour >= 6 && hour < 17)
{
return DAY;
}
else
{
return NIGHT;
}
}
int main()
{
Mage prototypeMage(100, 100, 80, "메이지");
Warrior prototypeWarrior(200, 50, 70, "워리어");
unique_ptr<Character> copyMage = prototypeMage.clone();
unique_ptr<Character> copyWarrior = prototypeWarrior.clone();
WeatherSubject weatherSubject;
weatherSubject.attach(copyMage.get());
weatherSubject.attach(copyWarrior.get());
copyMage->attack();
if (getHour() == DAY)
{
weatherSubject.setWeather(EEventType::DAY);
}
else if(getHour() == NIGHT)
{
weatherSubject.setWeather(EEventType::NIGHT);
}
return 0;
}

'Design Pattern' 카테고리의 다른 글
| Stategy pattern (0) | 2024.02.07 |
|---|---|
| State Pattern (0) | 2024.02.06 |
| Prototype Pattern (0) | 2024.02.04 |
| Builder Pattern (0) | 2024.02.03 |
| Factory Pattern (0) | 2024.02.02 |