前置き
今年の目標に小規模~中規模のリファクタリングができるようになることを設定しました。前回は1章で悪い構造の弊害を纏めました。2章の内容を纏めます。
2章 設計の初歩
- 省略せず意図が伝わる名前を設計する
int $d=0;
$d=$p1+$p2;
$d=$d-(($d1+$d2))/2);
if($d<0){
$d=0;
}
まったく意味が分からない。私も実務時foreach文内でほぼ同じものを見たことがあるので親近感感じる。
このコードの変数名を適切に記述すると・・・
int $damageAmount=0;
$damageAmount=$playerArmPower+$playerWeaponPower;
$damageAmount=$damageAmount-(($enemyBodyDefence+$enemyArmorDefence))/2);
if($damageAmount<0){
$damageAmount=0;
}
実はゲームのダメージ計算ロジックでした。コード見て一目でわかる。
さらに変数を使いまわし、\$damageAmountに計算結果を再代入している箇所を目的ごとの変数(\$totalPlayerAttackPower,\$totalEnemyDefence)に置き換えると
int $totalPlayerAttackPower=$playerArmPower+$playerWeaponPower;
int $totalEnemyDefence=$enemyBodyDefence+$enemyArmorDefence;
int $damageAmount=$totalPlayerAttackPower-($totalEnemyDefence/2);
if($damageAmount<0){
$damageAmount=0;
}
変数の関係が分かりやすくなったことが明確に分かる。
しかし、計算ロジックがべた書きのため、攻撃力、ダメージ量などの計算を別メソッド(method.php)に整理する。
//プレイヤーの攻撃力を合算
sumUpPlayerAttackpower(int $playerArmPower,int $playerWeaponPower):int{
return $playerArmPower+$playerWeaponPower;
}
//敵の防御力を合算
sumUpEnemyDefence(int $enemyBodyDefence,int $enemyArmorDefence):int{
return $enemyBodyDefence+$enemyArmorDefence;
}
//ダメージ量を計算
estimateDamage(int $totalPlayerAttackPower,int $totalEnemyDefence):int{
int $damageAmount=$totalPlayerAttackPower-($totalEnemyDefence/2);
if($damageAmount<0){
return 0;
}
return $damageAmount;
}
method.phpをadd_rename_value.phpに呼び出すと・・・
int $totalPlayerAttackPower=sumUpPlayerAttackpower($playerArmPower,$playerWeaponPower);
int $totalEnemyDefence=sumUpEnemyDefence($enemyBodyDefence,$enemyArmorDefence);
int $damageAmount=estimateDamage($totalPlayerAttackPower,$totalEnemyDefence);
初めのunknown_logic.phpと比べると同じコードで圧倒的に処理の流れが理解しやすく、保守変更がやりやすくなった。
- データとロジック(メソッド)はクラスに纏める
1章でまとめたようにデータとロジック(メソッド)が離れると重複や漏れにつながる。クラス化すると・・・
class DamageCalculate{
//コンストラクタ
function __construct(int $playerArmPower=0,int $playerWeaponPower=0,int $enemyBodyDefence=0,int $enemyArmorDefence=0){
$this->armpower=$playerArmPower;
$this->weaponpower=$playerWeaponPower;
$this->bodydefence=$enemyBodyDefence;
$this->armordefence=$enemyArmorDefence;
}
//プレイヤーの攻撃力を合算
final private sumUpPlayerAttackpower(int $playerArmPower,int $playerWeaponPower):int{
return $playerArmPower+$playerWeaponPower;
}
//敵の防御力を合算
final private sumUpEnemyDefence(int $enemyBodyDefence,int $enemyArmorDefence):int{
return $enemyBodyDefence+$enemyArmorDefence;
}
//ダメージ量を計算
final private estimateDamage(int $totalPlayerAttackPower,int $totalEnemyDefence):int{
int $damageAmount=$totalPlayerAttackPower-($totalEnemyDefence/2);
if($damageAmount<0){
return 0;
}
return $damageAmount;
}
}
$totalPlayerAttackPower=DamageCalculate::sumUpPlayerAttackpower(50,20);
$totalEnemyDefence=DamageCalculate::sumUpEnemyDefence(30,10);
$damageAmount=DamageCalculate::estimateDamage(10,10);
finalをメソッドにつけているため、別のクラスの同名関数による継承を防いでいる。それだけではなく、探し回ることが少なそうな保守、変更がしやすい構造に仕上がった。
感想
クラスにまとめるまでの流れは改めて勉強になった。
finalで他クラスで別の同名関数を宣言できないようにしておくのは参考になる実装だった。残りの章もアウトプットする。
参考書籍
良いコード悪いコードで学ぶ設計入門 著:仙塲大也