※ Strategy Pattern
전략패턴은 객체들의 행위를 각 전략 클래스에 생성, 유사행위를 캡슐화하는 인터페이스를 정의
객체의 행위를 동적으로 바꾸고 싶다면 전략만 바꿔줌으로 행위를 유연하게 확장하는 방법
클라이언트와 독립적으로 구현되기에 새로운 알고리즘 추가,변경이 쉬워진다.
[구조 예시]
#include <iostream>
using namespace std;
class SortBehavior {
public:
virtual void sort() const = 0;
};
class Merge: public SortBehavior {
public:
virtual void sort() const { cout << "Merge sort()" << endl; }
};
class Quick: public SortBehavior {
public:
virtual void sort() const { cout << "Quick sort()" << endl; }
};
class Heap: public SortBehavior {
public:
virtual void sort() const { cout << "Heap sort()" << endl; }
};
class SearchBehavior {
public:
virtual void search() const = 0;
};
class Sequential: public SearchBehavior {
public:
virtual void search() const { cout << "Sequential search()\n"; }
};
class BinaryTree: public SearchBehavior {
public:
virtual void search() const { cout << "BinaryTree search()\n"; }
};
class HashTable: public SearchBehavior {
public:
virtual void search() const { cout << "HashTable search()\n"; }
};
// Context
class Collection {
private:
SortBehavior *m_sort;
SearchBehavior *m_search;
public:
Collection(){}
void set_sort(SortBehavior *s) { m_sort = s; }
void set_search(SearchBehavior *s) { m_search = s; }
void sort() const { m_sort->sort(); }
void search() const { m_search->search(); }
};
int main(int argc, char *argv[])
{
Merge merge;
Quick quick;
Heap heap;
Sequential sequential;
BinaryTree binaryTree;
HashTable hashTable;
Collection colA;
colA.set_sort(&merge);
colA.sort();
Collection colB;
colB.set_search(&binaryTree);
colB.search();
}
※ Observer Pattern
객체의 변화를 관찰하는 observer들의 목록을 객체에 등록, 변화가 있을 때 함수를 이용해 관찰대상자가 직접 observer에게 통지해 그 객체에 의존성을 가진 다른 객체가자동으로 업데이트 하는 방식
[구조 예시]
● Generator: 관찰 대상자로 현재 관찰 대상자에 붙어있는 Observer들을 관리할뿐만 아니라 현재 관찰 대상자의 상태 정보를 얻기 위한 함수를 제공
상태 변화시 등록되어 있는 모든 관찰자들에게 상태 변화를 통지해주는 함수를 제공합니다.
● StringGenerator: Generator를 상속받는 실제 상태 정보를 가지고 있는 객체.
상태 변화가 발생하면 상태 변화를 통지해주는 함수를 호출.
● Observer: 관찰자들이 가져야 할 공통인터페이스를 정의.
● StringObserver: 관찰 대상자의 상태 정보를 가져와 자신의 상태와 동기화.
이 객체는 관찰 대상자의 string형을 모니터에 출력해주는 객체입니다.
● StringCountObsever: 마찬가지로 관찰 대상자의 상태 정보를 가져와 자신의 상태와 동기화 합니다.
이 객체는 관찰 대상자인 string형 문자열의 개수를 화면에 출력하는 객체
#include <iostream>
#include <list>
#include <string>
using namespace std;
class IObserver {
public:
virtual void Update(const string &message_from_subject) = 0;
virtual ~IObserver(){ };
};
class ISubject {
public:
virtual void Attach(IObserver *observer) = 0;
virtual void Detach(IObserver *observer) = 0;
virtual void Notify() = 0;
virtual ~ISubject(){};
};
/* Subject는 일부 중요한 state를 소유, state가 변경되면 observer에게 알림*/
class Subject : public ISubject {
public:
/* subscription 관리 함수 */
void Attach(IObserver *observer) override { list_observer_.push_back(observer); }
void Detach(IObserver *observer) override { list_observer_.remove(observer); }
void Notify() override {
list<IObserver *>::iterator iterator = list_observer_.begin();
HowManyObserver();
while (iterator != list_observer_.end()) {
(*iterator)->Update(message_);
++iterator;
}
}
void CreateMessage(string message = "Empty") {
this->message_ = message;
Notify();
}
void HowManyObserver() { cout << "There are " << list_observer_.size() << " observers in the list" << endl; }
/*
* 일반적으로 subscription logic은 Subject가 실제로 수행할 수 있는 작업의 일부이다.
* Subject는 일반적으로 중요한 일이 발생할 때마다 통지 방법을 작동시키는 중요한 business logic를 갖고 있다.
*/
void SomeBusinessLogic() {
this->message_ = "change message message";
Notify();
cout << "I'm about to do some thing important\n";
}
virtual ~Subject() { cout << "Goodbye, I was the Subject" << endl; }
private:
list<IObserver *> list_observer_;
string message_;
};
class Observer : public IObserver {
public:
Observer(Subject &subject) : subject_(subject) {
this->subject_.Attach(this); // this는 observer
cout << "Hi, I'm the Observer \"" << ++Observer::static_number_ << "\"" << endl;
this->number_ = Observer::static_number_;
}
virtual ~Observer() {
cout << "Goodbye, I was the Observer \"" << this->number_ << "\"" << endl;
}
void Update(const string &message_from_subject) override {
message_from_subject_ = message_from_subject;
PrintInfo();
}
void RemoveMeFromTheList() {
subject_.Detach(this); // this는 observer
cout << "Observer \"" << number_ << "\" removed from the list" << endl;
}
void PrintInfo() {
cout << "Observer \"" << this->number_ << "\": a new message is available --> " << this->message_from_subject_ << endl;
}
private:
std::string message_from_subject_;
Subject &subject_;
static int static_number_;
int number_;
};
int Observer::static_number_ = 0; // static멤버변수 초기화 방법
void ClientCode() {
Subject *subject = new Subject;
Observer *observer1 = new Observer(*subject);
Observer *observer2 = new Observer(*subject);
Observer *observer3 = new Observer(*subject);
Observer *observer4;
Observer *observer5;
subject->CreateMessage("Hello World! :D");
observer3->RemoveMeFromTheList();
subject->CreateMessage("The weather is hot today! :p");
observer4 = new Observer(*subject);
observer2->RemoveMeFromTheList();
observer5 = new Observer(*subject);
subject->CreateMessage("My new car is great! ;)");
observer5->RemoveMeFromTheList();
observer4->RemoveMeFromTheList();
observer1->RemoveMeFromTheList();
delete observer5;
delete observer4;
delete observer3;
delete observer2;
delete observer1;
delete subject;
}
int main() {
ClientCode();
}
※ Adapter Pattern
변환기처럼 서로 다른 두 인터페이스 사이 통신을 가능하게 해주는 디자인 패턴이다.프로그램에서 한 클래스의 인터페이스를 클라이언트로 사용하고자 하는 인터페이스로 변환 시 사용
또한 어댑터 패턴은 다중상속을 사용해 구현할 수도 있다.
[구조 예시]
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
/* Target: client code에서 사용되는 domain-specific interface를 정의한다. */
class Target {
public:
virtual std::string Request() const { return "Target: The default target's behavior."; }
virtual ~Target() = default;
};
/* Adaptee(기존객체)는 유용한 동작이 포함되어 있지만 interface가 기존client code와 호환되지 않는다.
* 따라서 client code가 Adaptee를 사용하려면 적응할 필요가 있다.
*/
class Adaptee {
public:
string SpecificRequest() const { return ".eetpadA eht fo roivaheb laicepS"; }
};
/* Adapter는 Adaptee의 interface가 Target's interface와 호환되게 한다. */
class Adapter : public Target {
private:
Adaptee *adaptee_;
public:
Adapter() { }
Adapter(Adaptee *adaptee) : adaptee_(adaptee) {}
string Request() const override {
string to_reverse = this->adaptee_->SpecificRequest();
reverse(to_reverse.begin(), to_reverse.end());
return "Adapter: (TRANSLATED) " + to_reverse;
}
};
/* client code는 Target interface를 따르는 모든 클래스를 지원한다. */
void ClientCode(const Target *target) { cout << target->Request(); }
int main() {
cout << "Client: I can work just fine with the Target objects:\n";
Target *target = new Target;
ClientCode(target);
cout << endl << endl;
Adaptee *adaptee = new Adaptee;
cout << "Client: The Adaptee class has a weird interface. See, I don't understand it: " << endl;
cout << "Adaptee: " << adaptee->SpecificRequest();
cout << endl << endl;
cout << "Client: But I can work with it via the Adapter: " << endl;
Adapter *adapter = new Adapter;
ClientCode(adapter);
cout << endl;
delete target;
delete adaptee;
delete adapter;
}
[다중상속으로 구현한 코드]
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
class Target {
public:
virtual string Request() const { return "Target: The default target's behavior."; }
virtual ~Target() = default;
};
class Adaptee {
public:
string SpecificRequest() const { return ".eetpadA eht fo roivaheb laicepS"; }
};
class Adapter : public Target, public Adaptee {
public:
Adapter() { }
string Request() const override {
string to_reverse = SpecificRequest();
reverse(to_reverse.begin(), to_reverse.end());
return "Adapter: (TRANSLATED) " + to_reverse;
}
};
void ClientCode(const Target *target) { cout << target->Request(); }
int main() {
cout << "Client: I can work just fine with the Target objects: " << endl;
Target *target = new Target;
ClientCode(target);
cout << endl << endl;
Adaptee *adaptee = new Adaptee;
cout << "Client: The Adaptee class has a weird interface. See, I don't understand it: " << endl;
cout << "Adaptee: " << adaptee->SpecificRequest();
cout << endl << endl;
cout << "Client: But I can work with it via the Adapter: " << endl;
Adapter *adapter = new Adapter;
ClientCode(adapter);
cout << endl;
delete target;
delete adaptee;
delete adapter;
}
'C | C++ > Modern C++' 카테고리의 다른 글
Design Pattern I_Singleton, Factory method, bridge pattern (0) | 2022.11.10 |
---|---|
C++로 Java와 동일한 로직을 구현해보자! (0) | 2022.11.02 |
[TCPL]_ 1부(prev) Tip 정리. (0) | 2022.11.01 |
[Effective Modern C++ item 1]: template 형식 연역 규칙을 숙지하라! (0) | 2022.10.28 |
☆Prev. C++, Modern C++의 변화 (2) | 2022.10.28 |