-
방문자 패턴(Visitor Pattern) c++ 예제프로그래밍/기록, 개념, 용어 2015. 12. 23. 18:59반응형방문자 패턴 없이 기능 구현을 했을 때123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153class account{public:account(string n) :customer_name_{ std::move(n) },money_{ 0 }{}~account(){}virtual int get_total_sum() const = 0;virtual void history_report() const = 0;virtual void total_sum_report() const = 0;list<int> history() const{return history_;}string customer_name() const{return customer_name_;}// 입금void deposit(int money){money_ += money;history_.push_back(money);}// 출금void withdraw(int money){money_ -= money;history_.push_back(-money);}protected:string customer_name_;int money_;list<int> history_;};class passbook_account : public account{public:passbook_account(string n) :account{ n }{}virtual int get_total_sum() const override{return money_;}virtual void total_sum_report() const override{printf("%s 님의 보유 금액: %d\n", customer_name_.c_str(), this->get_total_sum());}virtual void history_report() const override{printf("%s 님의 입출금 내역\n", customer_name_.c_str());for (const auto& elem: history_){printf("%d\n", elem);}}};class checking_account : public account{public:checking_account(string n) :account{ n }{}virtual int get_total_sum() const override{return money_ + (money_ * 0.1/*0.1% 이자*/);}virtual void total_sum_report() const override{printf("%s 님의 보유 금액: %d\n", customer_name_.c_str(), this->get_total_sum());}virtual void history_report() const override{printf("%s 님의 입출금 내역\n", customer_name_.c_str());for (const auto& elem : history_){printf("%d\n", elem);}}};void do_total_sum_report(list<account*>& accounts){for (auto& elem : accounts){elem->total_sum_report();}}void do_history_report(list<account*>& accounts){for (auto& elem : accounts){elem->history_report();}}int main(){passbook_account a{ "영희" };passbook_account b{ "철수" };checking_account c{ "영희엄마" };checking_account d{ "철수아빠" };/*철수는 엄마가 없고, 영희는 아빠가 없다*/list<account*> accounts;accounts.emplace_back(&a);accounts.emplace_back(&b);accounts.emplace_back(&c);accounts.emplace_back(&d);a.deposit(1000);b.deposit(2000);c.deposit(1500);d.deposit(2000);a.withdraw(500);c.withdraw(300);do_history_report(accounts);do_total_sum_report(accounts);return 0;}
cs 이 방식은 다음과 같은 문제점이 있다.
수행하고 싶은 작업의 종류가 계속 늘어날 경우,
기반 클래스에 가상함수를 추가하고, 상속 받는 클래스는 함수를 일일히 구현해야한다.
작업이 추가될 때마다 여러곳을 손봐야 하는 것이다.
방문자 패턴(visitor pattern)
눈여겨 볼 것이 있다. 우리가 하고자 하는 건, 데이터가 아닌 작업의 추가라는 것이다.
기존의 소스 코드에 영향을 주지 않고, 작업을 추가할 수 있는 방법은 뭘까?
작업 항목을 정의하고, 작업을 추가하는 것이다.
모든 작업은 기존의 데이터를 이용해 처리한다.
그렇다면 어떤 작업자 객체를 만들어, 대상 클래스의 데이터를 이용해 무언가를 하도록 만들면 된다.
여기서는 reporter로 구현이 되었다.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161class reporter;class passbook_account;class account;class checking_account;class account{public:account(string n) :customer_name_{ n },money_{ 0 },history_{}{}~account(){}virtual void accept(reporter& r) = 0;virtual int get_total_sum() const = 0;list<int> get_history() const{return history_;}string get_customer_name() const{return customer_name_;}void deposit(int money){money_ += money;history_.push_back(money);}void withdraw(int money){money_ -= money;history_.push_back(-money);}protected:list<int> history_;string customer_name_;int money_;};class reporter{public:virtual void visit_passbook_account(passbook_account* acc) = 0;virtual void visit_checking_account(checking_account* acc) = 0;};class passbook_account : public account{public:passbook_account(string n) :account{ n }{}virtual void accept(reporter& r) override{r.visit_passbook_account(this);}virtual int get_total_sum() const override{return money_;}};class checking_account : public account{public:checking_account(string n) :account{ n }{}virtual void accept(reporter& r) override{}virtual int get_total_sum() const override{return money_;}};class total_sum_reporter : public reporter{public:virtual void visit_passbook_account(passbook_account* acc) override{printf("%s 님의 보유 금액 %d\n", acc->get_customer_name().c_str(), acc->get_total_sum());}virtual void visit_checking_account(checking_account* acc) override{printf("%s 님의 보유 금액 %d\n", acc->get_customer_name().c_str(), acc->get_total_sum());}};class history_reporter : public reporter{public:virtual void visit_passbook_account(passbook_account* acc) override{printf("%s 님의 입출금 내역\n", acc->get_customer_name().c_str());for (auto& elem : acc->get_history()){printf("%d\n", elem);}}virtual void visit_checking_account(checking_account* acc) override{printf("%s 님의 입출금 내역\n", acc->get_customer_name().c_str());for (auto& elem : acc->get_history()){printf("%d\n", elem);}}};int main(){passbook_account a{ "영희" };passbook_account b{ "철수" };a.deposit(1000);a.deposit(200);b.deposit(10);b.withdraw(100);b.deposit(2000);history_reporter hr;hr.visit_passbook_account(&a);hr.visit_passbook_account(&b);total_sum_reporter sr;sr.visit_passbook_account(&a);sr.visit_passbook_account(&b);return 0;}cs 별다른 게 있는 건 아니다.c에서 c++ 클래스의 멤버 함수를 흉내내는 것과 비슷한 느낌.12345678910111213struct student{char name[20];int math;int science;int english;};void set_student_name(student* s, const char* name){strcpy(s->name, name); // 이런 거 같은!}cs 데이터를 제공하는 인스턴스는 방문자에게 데이터를 제공하는 인터페이스(getter)를 마련해 두어야 한다.
반응형'프로그래밍 > 기록, 개념, 용어' 카테고리의 다른 글
함수 호출 규약 vectorcall (0) 2016.04.17 컴포넌트 기반 설계 (0) 2016.04.05 데이터 통로 통신 시스템 (3) 2015.10.06 socket. shutdown과 close의 차이 (0) 2015.10.04 [스크랩] Graceful Shutdown에 관하여 (0) 2015.07.11