抽象クラス
CoddyのPHPジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 25/91。
抽象クラスは、直接インスタンス化できないクラスです。これは他のクラスの設計図として機能し、子クラスが実装しなければならないメソッドを定義します。abstractキーワードを使用して抽象クラスを作成します。
<?php
abstract class Shape {
protected $color;
public function __construct($color) {
$this->color = $color;
}
abstract public function calculateArea();
public function getColor() {
return $this->color;
}
}
class Rectangle extends Shape {
private $width;
private $height;
public function __construct($color, $width, $height) {
parent::__construct($color);
$this->width = $width;
$this->height = $height;
}
public function calculateArea() {
return $this->width * $this->height;
}
}
$rect = new Rectangle("blue", 5, 3);
echo $rect->calculateArea();
出力:
15Shapeクラスは、実装を提供せずに抽象メソッドcalculateArea()を宣言します。Shapeを継承するすべてのクラスは、このメソッドを実装しなければなりません。抽象クラスには、子クラスが直接継承するgetColor()のような通常のメソッドも含めることができる点に注意してください。
抽象メソッドは、子クラスが何をすべきかを定義しますが、その方法は定義しません。これにより、すべての図形が calculateArea() メソッドを持つことが保証され、同時に各図形がそれぞれの面積を異なる方法で計算できるようになります。
重要なポイント: 抽象クラスは、継承の構造と強制的な要件を組み合わせたものです。関連するクラス間でコードを共有しつつ、各子クラスで特定のメソッドが確実に実装されるようにしたい場合に使用します。
チャレンジ
簡単抽象クラスがどのように規約を強制し、異なるメディアタイプが独自の再生動作を実装できるようにするかを示すメディアプレーヤーシステムを構築しましょう。
コードは3つのファイルに分けて構成します:
Media.php— すべてのメディアタイプの設計図となる抽象クラスMediaを定義します。このクラスには、protectedな$titleプロパティと、タイトルを受け取って設定するコンストラクタを持たせる必要があります。子クラスが必ず実装しなければならないplay()という抽象メソッドを含めてください。また、タイトルを返す通常のメソッドgetTitle()も追加してください。この具象メソッドはすべての子クラスに継承されます。Song.php—Mediaを継承するSongクラスを定義します。ファイルの先頭で Media ファイルをインクルードしてください。このクラスには$artistプロパティを追加します。コンストラクタはタイトルとアーティストを受け取るようにし、タイトルにはparent::__construct()を使用し、アーティストは自身で設定します。要求されたplay()メソッドを実装し、"Playing song: [title] by [artist]"を返すようにします。Podcast.php—Mediaを継承するPodcastクラスを定義します。ファイルの先頭で Media ファイルをインクルードしてください。このクラスには$episodeプロパティ(整数)を追加します。コンストラクタはタイトルとエピソード番号を受け取るようにし、タイトルにはparent::__construct()を使用し、エピソードを設定します。要求されたplay()メソッドを実装し、"Playing podcast: [title] - Episode [episode]"を返すようにします。
main.php では、Song と Podcast の両方のファイルをインクルードします。4つの入力(曲のタイトル、アーティスト名、ポッドキャストのタイトル、エピソード番号(整数に変換する文字列として))を受け取ります。これらの値を使用して Song オブジェクトと Podcast オブジェクトを作成します。最初に曲の play() を呼び出した結果を、次にポッドキャストの play() を呼び出した結果を、それぞれ個別の行に出力してください。
このチャレンジは、抽象クラスがどのように規約を定義するかを示しています。すべてのメディアタイプは play() メソッドを持つ必要がありますが、各タイプで実装方法が異なります。抽象クラス Media は直接インスタンス化することはできません。これは、子クラスに構造と共有機能を提供するためにのみ存在します。
チートシート
抽象クラスは、直接インスタンス化できないクラスです。これは他のクラスの設計図として機能し、子クラスが実装しなければならないメソッドを定義します。抽象クラスを作成するには、abstractキーワードを使用します。
abstract class Shape {
protected $color;
public function __construct($color) {
$this->color = $color;
}
abstract public function calculateArea();
public function getColor() {
return $this->color;
}
}子クラスはすべての抽象メソッドを実装する必要があります:
class Rectangle extends Shape {
private $width;
private $height;
public function __construct($color, $width, $height) {
parent::__construct($color);
$this->width = $width;
$this->height = $height;
}
public function calculateArea() {
return $this->width * $this->height;
}
}主な特徴:
- 抽象クラスは直接インスタンス化できません
- 抽象メソッドは、抽象クラス内では実装を持ちません
- 子クラスはすべての抽象メソッドを実装する必要があります
- 抽象クラスには、抽象メソッドと通常のメソッドの両方を含めることができます
- 抽象クラス内の通常のメソッドは、子クラスに継承されます
自分で試してみよう
<?php
require_once 'Song.php';
require_once 'Podcast.php';
// 入力を読み込む
$songTitle = trim(fgets(STDIN));
$artistName = trim(fgets(STDIN));
$podcastTitle = trim(fgets(STDIN));
$episodeNumber = intval(trim(fgets(STDIN)));
// TODO: songTitleとartistNameを使用してSongオブジェクトを作成する
// TODO: podcastTitleとepisodeNumberを使用してPodcastオブジェクトを作成する
// TODO: songに対してplay()を呼び出した結果を出力する
// TODO: podcastに対してplay()を呼び出した結果を出力する
?>このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。