このサンプルコードでは、、手続き的凝集のクラスが複数の異なる責務を担当している状況を示します。
OrderProcessingクラスが注文処理、顧客情報の更新、請求書の生成という異なる責務を持っています。
このようなクラスは手続き的凝集を示しており、下記のような問題が発生します。
<?php
class OrderProcessing
{
public function processOrder($orderData)
{
// 注文処理の論理
}
public function updateCustomerInfo($customerData)
{
// 顧客情報の更新処理
}
public function generateInvoice($orderData)
{
// 請求書の生成処理
}
}
<?php
$orderProcessor = new OrderProcessing();
$orderData = /* 注文データ */;
$customerData = /* 顧客情報 */;
$orderProcessor->processOrder($orderData);
$orderProcessor->updateCustomerInfo($customerData);
解決策として、それぞれの責務に特化したクラスを作成し、各クラスが単一の責務を担当するように設計することが考えられます。
このように設計を改善することで、手続き的凝集の問題を克服できます。
改修の際には、クラスを分割し、それぞれのクラスが特定の責務を担当するように設計することが重要です。例えば、OrderProcessingクラスを以下のようなクラスに分割できます。
下記の改善された設計において、各クラスは単一の責務を担当しており、クラス間の結合度が低く、変更が特定の責務に関連付けられます。
このような設計は保守性が高く、テストも容易に行えます。
<?php
class OrderProcessor
{
public function processOrder($orderData)
{
// 注文処理の論理
}
}
<?php
class CustomerInfoUpdater
{
public function updateCustomerInfo($customerData)
{
// 顧客情報の更新処理
}
}
<?php
class InvoiceGenerator
{
public function generateInvoice($orderData)
{
// 請求書の生成処理
}
}
<?php
$orderProcessor = new OrderProcessor();
$customerInfoUpdater = new CustomerInfoUpdater();
$invoiceGenerator = new InvoiceGenerator();
$orderData = /* 注文データ */;
$customerData = /* 顧客情報 */;
$orderProcessor->processOrder($orderData);
$customerInfoUpdater->updateCustomerInfo($customerData);
$invoiceGenerator->generateInvoice($orderData);
動詞で名付けられたクラスは、一般的にそのクラスが特定の操作やプロセスを実行することを示しています。
クラス名そのものがプロセスに焦点にされているため、その性質上手続き的凝集になりやすい傾向にあります。
このようなクラスは、操作やプロセスを単一の責務として持つべきで、手続き的凝集を避けるために注意が必要です。
また、手続き的凝集を避けるために、クラス名が特定の操作やプロセスを示さないようにすることも一つのアプローチです。
クラス名が動詞ではなく、名詞またはドメインに焦点を当てたものであると、手続き的凝集を回避しやすくなります。