独学エンジニアという学習サイトで「関数の凝集度」について学んだ内容を、自分用の備忘録としてまとめています。
PHPで関数を設計するとき、「どんな関数が良い関数なのか?」の判断基準の1つが「凝集度」です。
今後の実装やリファクタリング時に役立つよう、ポイントを整理しました。
概要
関数を設計するときに、
「どんな関数が良い関数なのか?」を判断する指標の一つが「凝集度」です。
凝集度(ぎょうしゅうど、cohesion)とは?
関数内の処理がどれだけ密に関連しているかを表す概念
凝集度が高い関数
- やることが明確 で理解しやすい
- 再利用しやすい
- テスト・保守がしやすい
凝集度が低い関数
- 関数の目的が不明確
- 再利用しにくい
- 修正・バグ修正が困難になる
関数を設計するときは、できるだけ凝集度を高めることが重要です。
それでは、具体的に見ていきましょう
凝集度の高い関数ほど「良い関数」
凝集度の種類(高い → 低い順)
高いほど「良い関数」
低くなるほど「修正・テスト・再利用が難しくなる」
凝集度の種類 | 説明 | 例 |
---|---|---|
① 機能的凝集度(理想形) | 単一のタスクを実行 する関数 |
getUserName() , calculateTotalPrice()
|
② 情報的凝集度(関連性が強い) | 同じデータを使うが、処理が複数ある | getAgeAndRetirementYears() |
③ 連絡的凝集度(データ共有) | 同じデータを扱うが、関連性が低い | savePurchasedItem() & removeFromCart() |
④ 手順的凝集度(順番のみ関係) | 処理に関連はないが、実行順が決まっている | getUserName() -> getUserAddress() |
⑤ 時間的凝集度(一緒に実行される) | 同時に実行されるが関連性は低い | initializeSystem() |
⑥ 論理的凝集度(条件分岐で処理を決定) | フラグで処理を切り替える | saveData(type) |
⑦ 暗号的凝集度(NG!) | 関係ない処理を無理にまとめた関数 |
processData() (何をするのか不明) |
2️各凝集度の詳細 & 改善方法
機能的凝集度(理想形)
1つの関数が「1つの役割」を持つ → 理想的な関数!
// 良い例:単一のタスクを実行する関数
function getUserName($user) {
return $user['name'];
}
function calculateTotalPrice($items) {
$total = 0;
foreach ($items as $item) {
$total += $item['price'];
}
return $total;
}
1つの関数で1つの処理をする → 理解しやすい
テストや修正が容易 → 保守しやすい
情報的凝集度(関連性の強い処理)
関連性の高い複数の処理をまとめた関数
function getAgeAndRetirementYears($birthYear, $retirementAge = 65) {
$age = date('Y') - $birthYear;
$yearsToRetire = $retirementAge - $age;
return [$age, $yearsToRetire];
}
年齢と定年までの年数 → 密接に関連
1つの関数にしても理解しやすい
さらにシンプルにするなら、2つの関数に分けるのもアリ
③ 連絡的凝集度(データを共有するが処理は独立)
同じデータを扱うが、処理としては別のもの
function savePurchasedItem($item) {
// 商品をDBに保存
}
function removeFromCart($item) {
// カートから削除
}
処理を分けることで、メンテナンス性が向上
④ 手順的凝集度(順番があるだけで関連性が薄い)
実行順は決まっているが、処理自体の関連性は薄い
function getUserData() {
$name = getUserName();
$address = getUserAddress();
}
改善方法 → 関数を個別に呼び出せるようにする
時間的凝集度(同時に実行するが関連が低い)
初期化処理などで発生しがち
function initializeSystem() {
loadConfig();
connectDatabase();
startSession();
}
改善方法 → 各処理を個別の関数にして、まとめる関数を用意
論理的凝集度(制御フラグで処理を決定)
フラグの値で処理が変わる関数(NGパターン)
function saveData($type, $data) {
if ($type == 'user') {
saveUser($data);
} elseif ($type == 'order') {
saveOrder($data);
}
}
改善方法 → フラグで処理を切り替えるのではなく、関数を分ける
function saveUser($data) {
// ユーザー情報を保存
}
function saveOrder($data) {
// 注文情報を保存
}
暗号的凝集度(NG)
複数の無関係な処理をまとめた関数(最悪なパターン)
function processEverything() {
getUserName();
calculateDiscount();
sendEmail();
}
改善方法 → 何をする関数なのかを明確にし、分ける
まとめ
関数の「凝集度」を意識して設計しよう
「1つの関数は1つの役割」を意識
凝集度の高い関数を作るほど、可読性・再利用性・保守性が向上
機能的凝集度(1つの処理だけを行う関数)を目指す
論理的凝集度や暗号的凝集度にならないように注意
整理した内容は以上です。
関数の凝集度を意識することで、コードの保守性・可読性・再利用性が大きく向上するので、
今後のPHP開発において、「関数をどう設計するか」を考えるヒントになればと思います。
この記事が、PHPを学習中の方や同じように独学でプログラミングを学ぶ方の参考になれば幸いです。