はじめに
最近、「オブジェクト設計スタイルガイド」を読んでいるので、本書の中で自分が疑問に感じたポイントをQ&A形式で振り返ってみたいと思います。
この記事では、各セクションの簡単な説明の後に、[Q]で疑問に感じたこと、[A]で調べてわかったこと、そして[NOTE]で覚えておきたいことをまとめています。
なお、サンプルコードにPHPを使用していますが、言語を問わず広く有効な設計手法なので、他言語でも応用できる内容になっています。
7~8章については、すでに別の記事にまとめているので、こちらもぜひご覧ください!
それでは、9〜10章を振り返りながら、一緒に「オブジェクト設計」について学んでいきましょう!
デコレーターパターン
デコレーターパターンは、既存のクラスやオブジェクトに対して、元の構造を変更せずに新しい機能を動的に追加できるデザインパターンです。
新しい機能を追加するためにサブクラス化する代わりに、既存のオブジェクトをラップ(包む)して機能を拡張します。
例えば、ReportGenerator
インターフェースを実装した以下のようなPDFレポートを生成する PdfReportGenerator
クラスがあり、レポートを生成する処理の前後にログが出力されるようにしたいとします。
<?php
interface ReportGenerator
{
public function generate(): string;
}
class PdfReportGenerator implements ReportGenerator
{
public function generate(): string
{
return "PDFレポートを生成しました。";
}
}
$pdfReportGenerator = new PdfReportGenerator();
echo $pdfReportGenerator->generate();
// 実行結果:
// PDFレポートを生成しました。
このときに、既存のクラスをラップするデコレータパターンを使用すると、元のクラスを変更せずに、レポートを生成する処理に対して「ログを記録する機能」を後付けできるようになります。
class ReportGeneratorWithLogging implements ReportGenerator {
public function __construct(private ReportGenerator $reportGenerator)
{
}
public function generate(): string
{
echo "[LOG] レポートの生成を開始しました。\n";
$generatedReport = $this->reportGenerator->generate();
echo "[LOG] レポートの生成を終了しました。\n";
return $generatedReport;
}
}
$pdfReportGenerator = new PdfReportGenerator();
$reportGeneratorWithLogging = new ReportGeneratorWithLogging(
$pdfReportGenerator
);
echo $reportGeneratorWithLogging->generate();
// 実行結果:
// [LOG] レポートの生成を開始しました。
// [LOG] レポートの生成を終了しました。
// PDFレポートを生成しました。
[NOTE]
デコレーターパターンのメリットは以下の通りです。
- オブジェクトのクラスを変更せずに、必要な機能だけを後から動的に付け加えられる。
- オープン/クローズド原則に準拠しているので、元のクラスは修正せずに拡張できる。
- 単一責務を維持しているので、クラスが肥大化せず、テストや保守も簡単です。
- 以下のように複数のデコレーターの順番を変えて柔軟に組み合わせることができる。
$pdfReportGenerator = new PdfReportGenerator();
$generator = new ReportGeneratorWithLogging($pdfReportGenerator);
$generator = new ReportGeneratorWithCaching($generator);
$generator = new ReportGeneratorWithSecurity($generator);
レイヤ
インフラストラクチャレイヤ
データベース、ファイル、Web APIなど、外部のリソースとのやりとりを実際に行うレイヤ。
アプリケーションレイヤ
ユーザーや外部からのリクエストに応じて、ドメインロジックを使いながら処理を進める。
つまり、ユースケースの実行管理を担当します。
ドメインレイヤ
アプリケーションの中核となるビジネスロジックを担当します。
[NOTE]
今まで学習したオブジェクト群はレイヤを形成する。
インフラストラクチャレイヤ
- コントローラ
- ライトモデルリポジトリとリードモデルリポジトリの実装
アプリケーションレイヤ
- アプリケーションサービス
- コマンドオブジェクト
- リードモデル
- リードモデルリポジトリのインタフェース
- イベントリスナ
ドメインレイヤ
- エンティティ
- バリューオブジェクト
- ライトモデルリポジトリのインタフェース
おわりに
今回は、「オブジェクト設計スタイルガイド」の9~10章を題材に、自分が疑問に感じたポイントを紹介しました。
デコレーターパターンやレイヤ構造など、設計の基本を振り返るきっかけになればと思います!
なお、「現場で役立つシステム設計の原則」の第1~2章の記事も公開しているので、ぜひあわせてご覧ください!