※ 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;
}

 

+ Recent posts