2010年5月26日水曜日

C++でTemplateMethodパターン

TemplateMethodパターンはスーパークラス(ベースクラス)でロジックの概要設計あるいは共通部分を実装し、詳細ロジックあるいは非共通部分をサブクラスで提供するパターンです。
大げさに言うとスーパークラスでプチフレームワークを実装するようなイメージです。
TemplateMethodパターンのメリットは
  • サブクラスで共通なロジックをスーパークラスで共通化できる。
  • ロジックの骨組みが明確になっている為、コードが把握し安い且つメンテナンスコストが軽減されやすい。
などです。
それではクラス図をご覧ください。
ちょっとメソッドとか多いですけど簡単な継承関係です。
このクラス図で重要なのは
  • move()
  • canMove()
  • canMoveEach()
  • moveEach()
で、Characterクラスのmove()がテンプレートメソッドに相当します。
次にソースを見てみましょう、用意するのは次のファイルです今回からクラスのcppファイルを用意しない方が見やすいかなと思って.hだけ用意しました。
  • main.cpp
  • Character.h
  • Monster.h
Character.h
#ifndef _CHARACTER_H_
#define _CHARACTER_H_

#include 

class Character
{
    //----------------------------------
    //  field
    //----------------------------------
private:
    int HP;
    int MP;

    //----------------------------------
    //  property
    //----------------------------------
public:
    const int getHP() {
        return this->HP;
    }
    Character& setHP(const int _hp) {
        this->HP = _hp;
        return *this;
    }
    const int getMP() {
        return this->MP;
    }
    Character& setMP(const int _mp) {
        this->MP = _mp;
        return *this;
    }

    //----------------------------------
    //  method
    //----------------------------------
public:
    Character() :
        HP(100),
        MP(100)
    {
        //  do nothing...
    }

    virtual ~Character() {
        //  do nothing...
    }

    void move() {   //  テンプレートメソッド
        //  move可能判定
        if (this->canMove()) {
            //  move
            this->moveEach();
        }
    }
private:
    virtual const bool canMove() {
        //  HPが0ならmove不可
        if (this->getHP() <= 0) {
            return false;
        }
        return this->canMoveEach();
    }

protected:
    virtual const bool canMoveEach() = 0;
    virtual void moveEach() = 0;
};
#endif
move()のなかでmove可能ならばmoveするという大まかなロジックを実装しています。

Monster.h
#ifndef _MONSTER_H_
#define _MONSTER_H_

#include "Character.h"

class Monster : public Character
{
 //----------------------------------
 // method
 //----------------------------------
protected:
 virtual ~Monster() {
  // do nothing...
 }
 virtual const bool canMoveEach() {
  printf("canMoveEach\n");
  return true;
 }

 virtual void moveEach() {
  printf("moveEach\n");
 }
};
#endif
Monster独自のcanMove()、move()をcanMoveEach()、moveEach()で実装しています。Eachっていう名前の付け方は一般的ではない気がします。

main.cpp
#include 
#include "Monster.h"

void main(void)
{
    //  Monster生成
    Character* character = new Monster();

    //  move
    character->move();

    //  HPに0を設定
    character->setHP(0);

    //  move
    character->move();

    delete character;
    printf("hit any key...\n");
    while(getchar() == EOF) {}
}

0 件のコメント:

コメントを投稿