0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

社内勉強会議事録 - 2 クラスをどこまで細かくするか ~値オブジェクト~

Posted at

目次

1. はじめに

会社で第2回の勉強会を主催したので学習内容のメモとなります。
タイトルの通りクラス設計に関する勉強会を開きました。

2. 概要

今回のテーマは、値オブジェクトです。
今回の記事は、RPGゲームにおけるステータスを題材とし内容を進めていきます。
内容は次のとおりです。

  1. 値オブジェクトの概要
  2. 値オブジェクトのメリット
  3. 値オブジェクトの難しいところ

※解釈がずれている箇所がありましたら教えていただければと思います。
参考資料[1]:「良いコード/悪いコードで学ぶ設計入門 ―保守しやすい 成長し続けるコードの書き方」
題材1.png

3 内容:値オブジェクト

3.1 値オブジェクトの概要

値オブジェクト:値をクラスとして表現する設計パターン
金額、日付、注文数、電話番号などさまざまな形をとる。
入門書などでは型がプリミティブ型で表現されるものが多いと思うが、
値オブジェクトはここが自作のクラスになります。

値オブジェクトプリミティブ.png

値オブジェクトの構成要素(自己防衛責務を持ったクラスの条件)

  • インスタンス変数を初期化するコンストラクタ
  • インスタンス変数のバリデーション
  • インスタンス変数を不変状態にする
  • インスタンス変数を正常に操作するメソッドをもつ
    ※参考文献1ではインスタンス変数を1つにすることが望ましいと書いてありました。
public class Player { // 立場的にはエンティティ
    HP hp;
    MP mp;

    public void healHP(final int heal) {
        hp = hp.heal(heal);
    }
}

public class HP { // 値オブジェクト
	private final int hp;

	public HP(final int hp) {
		if(hp > -1) {
			this.hp = hp;
		}
		else {
			// 例外処理
		}
	}

	public HP heal(int heal) {
		return new HP(this.hp + heal);
	}
}

3.2 値オブジェクトの強み

  1. 誤った代入を防ぐ
  2. 表現力
  3. ロジックの分散を防ぐ 前回の話
  4. 不正値を防ぐ 前回の話

1と2について説明

3.3 誤った代入を防ぐ

image.png
勇者の残りHPは10だ!!
勇者は回復魔法を唱えた 170回復した
勇者のHPは10になった 
勇者は回復したはずなのになぜだろう?

型がintだと整数なら何でも入ってしまう → IDE的には正しい
MPを表す変数にHPの状態が入っても気づけない → ヒューマンエラー

public class Player {
    int hp;
    int mp;

    public void healHP(final int heal) {
        this.mp = this.hp + heal;
    }
}

image.png

値オブジェクトなら代入時に型が違うのでエラーが出る
プリミティブ型ではなくユーザー定義クラスを使うのが1番のポイント。
image.png

3.4 表現力

名前設計に不慣れでも読み手に型で情報を与えられるのがよい。

int rest = healHP();

プリミティブで表現した場合返却の可能性は2つ

  1. 回復後の残りHP
  2. 回復後の残りMP
HP rest = healHP();

値オブジェクトの場合あ1つに絞れる
1.回復後の残りHP

3.5 値オブジェクトの難しいところ

  • 数十行のクラスが数十~数百も作られる → 設計書の更新などが大変
  • どこまで細かく分けるかだと思います

例えば先ほど使ったこのコード、これってそもそもよさげ?

public class Player { // 立場的にはエンティティ
    HP hp;
    MP mp;

    public void healHP(final int heal) {
        hp = hp.heal(heal);
    }
}

1値=1フィールドで考えた場合これから巨大化していきそうですね。

public class Player {
    HP hp;
    MP mp;
    攻撃力;
    防御力;
    魔法攻撃力;
    魔法防御力;
    アイテムボックス;
    武器右手
    武器左手
    ヘルム
    
    レッグ
    アクセサリー

    // メソッド
}

ゲームだとステータスや装備ってまとまって管理されていることが多いのでは?
次のような感じで分けてみたけどこれも結局コンテキストによる。
やはりどうやって分けるのかが難しそうです。

class Player {
    private Status status;       // ステータス
    private Equipment equipment; // 装備
    public Player(HP hp, MP mp){
        status = new Status(hp, mp);
    }
}
class Status {  
    final HP hp;
    final MP mp; 
    Status(final HP hp, final MP mp) {
        // バリデーション
        this.hp = hp;
        this.mp = mp;
    }
}

4 まとめ

今回のゴール:クラスをどのくらい細かく設計するか
値オブジェクトという考え方を知ろう
→1つの属性を計測したり定量化したり説明したりするくらいまで
 値をクラスとして表現する設計パターン

値オブジェクトのメリット

  1. 誤った代入を防ぐ   :型でヒューマンエラーを防ぐ
  2. 表現力        :型で情報を与える
  3. ロジックの分散を防ぐ :1か所に集中できる
  4. 不正値を防ぐ     :状態変化が1度のみで安心

5. 参考文献

  1. 良いコード/悪いコードで学ぶ設計入門 ―保守しやすい 成長し続けるコードの書き方
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?