ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 방문자 패턴(Visitor Pattern) c++ 예제
    프로그래밍/기록, 개념, 용어 2015. 12. 23. 18:59
    반응형
    방문자 패턴 없이 기능 구현을 했을 때

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    class 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로 구현이 되었다.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    class 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++ 클래스의 멤버 함수를 흉내내는 것과 비슷한 느낌.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    struct 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)를 마련해 두어야 한다.

    반응형
Designed by Tistory.