2014年12月3日水曜日

カプセル化の意義をRPG風にたとえてみた

なぜクラスをカプセル化する必要があるのか疑問に感じる人も多いのではないでしょうか。

カプセル化とはインスタンス変数をprivateにして、直接アクセスできないようにし、メソッドを通じてのみ扱えるようにすることです。

では、これをRPG風に例えて説明してみましょう。

戦士のステータスとして「力」「武器の強さ」「攻撃力」を持っているとします。

これをクラスにするとこんな感じ

class Fighter {

  //力
  int strength;

  //武器の強さ
  int weapon;

  //攻撃力
  int attack;
}


大体のRPGでは「攻撃力」は「力」と「武器の強さ」の合計で決まるので、このクラスもそうしたい…

でも、現状の書き方では以下のように設定できてしまいます。


//戦士ジョンを生成
Fighter jon = new Fighter();

//ジョンの力を「10」に設定
jon.strength = 10;

//ジョンの武器の強さを「25」に設定
jon.weapon = 25;

//ジョンの攻撃力を「99」に設定??
//10 + 25で35じゃないの??
jon.attack = 99;



この場合は「攻撃力」を直接設定できてしまうので、ありえない値にできてしまう…

だったら、「攻撃力」は直接アクセスできないようにして、「力」または「武器の強さ」を設定したら自動的に計算してくれるようにしてしまえ!

それを踏まえたクラスがこちら

class Fighter {

  //力(直接アクセスできない)
  private int strength;

  //武器の強さ(直接アクセスできない)
  private int weapon;

  //攻撃力(直接アクセスできない)
  private int attack;


  //力を設定するメソッド
  void setStrength(int strength) {
 
    //力を設定
    this.strength = strength;
 
    //攻撃力を設定
    setAttack();
  }

  //武器の強さを設定するメソッド
  void setWeapon(int weapon) {
 
    //武器の強さを設定
    this.weapon = weapon;
 
    //攻撃力を設定
    setAttack();
 
  }

  //攻撃力を設定(他のクラスからは呼べない)
  private setAttack() {
 
    //攻撃力 = 力 + 武器の強さ
    attack = strength + weapon;
  }

  //攻撃力を取得
  int getAttack() {
    return attack;
  }
}


このクラスであれば、設定できるのは力と武器の強さだけで攻撃力は自動で計算してくれることになる

//戦士ジョンを生成
Fighter jon = new Fighter();

//ジョンの力を「10」に設定
jon.setStrength(10);

//ジョンの武器の強さを「25」に設定
jon.setWeapon(25);

//攻撃力は35と表示される
System.out.printf("攻撃力は%d", getAttack());





さらに、攻撃力の計算を「力」+「武器の強さ」の2倍に変更したい場合は、Fighterクラスの「setAttac()」を修正するだけで済みます。



//FighterクラスのsetAttackを修正
private setAttack() {

  //攻撃力 = (力 + 武器の強さ)の2倍に修正
  attack = (strength + weapon) * 2;
}



/*
  以下のコードはそのまま
*/

//戦士ジョンを生成
Fighter jon = new Fighter();

//ジョンの力を「10」に設定
jon.setStrength(10);

//ジョンの武器の強さを「25」に設定
jon.setWeapon(25);

//攻撃力は70と表示される
System.out.printf("攻撃力は%d", getAttack());


このようにあるステータスに対する約束事を必ず守らせるため、カプセル化しておくとそうすることしかできなくなるので、間違いが無くなる。

変更する場合でも、Fighterクラス側を修正するだけで良くなり保守性高まる。

つまり、カプセル化したほうが便利ですよね?

0 件のコメント:

コメントを投稿