💭
フィールドに持つべきか?メソッドで判定すべきか?
「この判定はフィールドに持っておけば効率的だし、メソッド呼び出しも減るはず」
と思い、安易にフラグを定義してみたら「本当に効率的になった?」とモヤっとした。
なぜモヤっとしたのか頭の中を整理してみた。
なぜモヤっとするのか?
1. 状態の重複・冗長性
メソッドで動的に判定できる情報をフィールドとして持つと、同じ情報を二重管理することになる。
// 判定メソッドあり
boolean isIrregular() { ... }
// フィールドも保持
boolean irregularFlag;
どちらかが更新されないと矛盾が発生し、不具合の原因になりやすい。
2. 保守性の低下
フィールドの値がどこで設定・更新されるか追う必要があり、複雑な処理では理解コストが増えてしまう。
複数箇所で更新されるフィールドは「うっかり更新漏れ」「順序依存のバグ」を引き起こしやすい。
3. テストの複雑化
フィールド依存のロジックは、テスト時に状態を準備する必要がある。
本来なら「メソッドを呼べば結果が返る」だけで済むテストが煩雑になる。
フィールド化の前にできる方法
1. メソッドのオーバーライド
class Employee {
boolean isIrregular() { return false; }
}
class IrregularEmployee extends Employee {
@Override
boolean isIrregular() { return true; }
}
サブクラスで振る舞いを変えつつ、状態の二重管理を避けられる。
2. 計算による判定
軽量な判定は、必要なときにメソッドで計算するだけで十分。
- フィールドを増やすより保守性が高い
- 判定ロジックの変更もメソッド内で完結する
3. 戦略の注入(Strategy Pattern)
class Employee {
private IrregularPolicy policy;
boolean isIrregular() {
return policy.isIrregular(this);
}
}
判定基準が変わる可能性がある場合、状態を持たず柔軟に対応できる。
あえてフィールドを持つ場合
-
計算コストが高い場合
一度計算した結果を保持する方が効率的 -
外部から値が注入される場合
DIや設定値など、外部から与えられる情報はフィールドとして保持 -
オブジェクトの状態として自然に保持すべき場合
画面表示のために一時的に必要な状態など
まとめ
- 原則:計算できるものは状態として持たない
- 対応方法:メソッドのオーバーライド、計算による判定、戦略の注入
- 例外:キャッシュが必要な場合、外部値の注入、オブジェクトの状態として保持すべき場合
この考え方を意識すれば、コードはシンプルで理解しやすく、長期的に変更しやすいシステムを作れる。
柔軟性と効率性のバランスを見極めて、必要に応じてフィールドを持つ判断を行う。
状態管理を考えるきっかけになった。
Discussion