コンポジションと継承
CoddyのPHPジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 56/91。
前の章では、トレイトが「has-a」能力を提供し、継承が「is-a」関係を確立することを学びました。コンポジションは、単純なオブジェクトから複雑なオブジェクトを構築し、それらを継承するのではなくプロパティとして格納することで、「has-a」という概念をさらに発展させます。
継承では、CarはVehicleを拡張することがあります。コンポジションでは、CarはEngineオブジェクトを含みます。
<?php
class Engine {
public function start(): string {
return "Engine started";
}
}
class Car {
private Engine $engine;
public function __construct() {
$this->engine = new Engine();
}
public function start(): string {
return $this->engine->start();
}
}
$car = new Car();
echo $car->start();
出力:
Engine startedCar クラスは Engine から継承するのではなく、それを所有します。このアプローチには大きな利点があります。エンジンを別の実装に置き換えられ、クラス間の結合度が低く保たれ、深い継承によって生じる柔軟性のない階層構造を避けられます。
OOPにおける一般的な指針は、「継承よりもコンポジションを優先する」ことです。継承は本当の型階層(Dogは実際にAnimalである)には適していますが、独立した部分から機能を組み立てる場合はコンポジションが力を発揮します。複数のオブジェクトを組み合わせたり、実行時に置き換えたり、コンポーネントを単独でテストしたりできます。
次のレッスンでは、オブジェクトが依存関係を受け取る方法を制御することで、コンポジションを直接発展させる依存性注入について学びます。
チャレンジ
簡単composition を使用して computer system を構築しましょう。ここでは、Computer は別々の component objects から組み立てられ、それらを継承するのではありません。これは、composition によって、より単純で独立した部分から複雑な objects を構築できることを示しています。
コードを3つのファイルに整理します。
Processor.php: CPU を representing するProcessorclass を Create します。constructor promotion を使用して、private$model(string)と private$cores(integer)を define します。"[model] ([cores] cores)"を返す methodgetSpecs()を追加します。Memory.php: RAM を representing するMemoryclass を Create します。constructor promotion を使用して、GB を representing する private$size(integer)を define します。"[size]GB RAM"を返す methodgetCapacity()を追加します。main.php: 両方の component files を Include し、composition を使用するComputerclass を Create します。Computerは次のようにします。Processorobject とMemoryobject を private properties として保存する- constructor で processor model、core count、memory size を accept する
- constructor の実行中に component objects を internally Create する
"Computer with [processor specs] and [memory capacity]"を返すdescribe()method を持つ
3つの入力、つまり processor model、cores の数、GB 単位の memory size を受け取ります。これらの仕様で
Computerを Create し、describe()を呼び出した result を print します。
Computer が Processor や Memory を extend していないことに注目してください。contains しているのです。この composition による「has-a」relationship によって、各 component は independent かつ reusable に保たれ、必要に応じて Computer がその parts に処理を Delegate できるようになります。
自分で試してみよう
<?php
require_once 'Processor.php';
require_once 'Memory.php';
class Computer
{
// TODO: Processor と Memory オブジェクトを格納する private プロパティを定義する
// TODO: コンストラクタはプロセッサモデル、コア数、メモリサイズを受け取るべき
// そしてコンポーネントオブジェクトを内部で作成する
public function __construct()
{
// TODO: Processor と Memory オブジェクトを作成して格納する
}
// TODO: 次を返す describe() メソッドを実装する
// "Computer with [processor specs] and [memory capacity]"
public function describe(): string
{
// TODO: コンポーネントオブジェクトに委譲し、フォーマットされた文字列を返す
}
}
// 入力を読み取る
$processorModel = trim(fgets(STDIN));
$cores = intval(fgets(STDIN));
$memorySize = intval(fgets(STDIN));
// TODO: 指定された仕様で Computer を作成し、describe() の結果を出力する
?>このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: PHPオンラインコンパイラ