PHPにおけるOOPでのインターフェースの応用
さて、インターフェースはクラスに必要なメソッドがすべて実装されていることを制御する良い方法であることをすでに確認しました。
さらに、より実践的な別の例を見てみましょう。図形オブジェクトの配列を保持するクラスがあるとします:
<?php
class FiguresCollection
{
private $figures = []; // 図形用の配列
}
?>
コレクションにオブジェクトを追加するためのメソッド addFigure をクラスに実装しましょう:
<?php
class FiguresCollection
{
private $figures = [];
// パラメータとして図形オブジェクトを渡します:
public function addFigure($figure)
{
$this->figures[] = $figure;
}
}
?>
明らかに、メソッド addFigure のパラメータには図形オブジェクトが渡されることを想定しています。しかし、これに対する制御は一切ありません!
型ヒントを使用して、オブジェクトの型を明示的に Figure として指定しましょう:
<?php
class FiguresCollection
{
private $figures = [];
public function addFigure(Figure $figure)
{
$this->figures[] = $figure;
}
}
?>
私たちが行ったことを整理してみましょう。
もし Figure が実際に存在するクラスであれば、メソッドのパラメータにはそのクラスのオブジェクトやその子クラスのオブジェクトを渡すことができたでしょう。
しかし、私たちの場合、 Figure はインターフェースです。その場合、型ヒントは、メソッドのパラメータとして渡せるのは、私たちのインターフェースを実装しているクラスのオブジェクトのみであることを示しています。
クラスのオブジェクトを作成し、それに図形を追加してみましょう:
<?php
$figuresCollection = new FiguresCollection;
// 正方形を2つ追加:
$figuresCollection->add(new Quadrate(2));
$figuresCollection->add(new Quadrate(3));
// 長方形を2つ追加:
$figuresCollection->add(new Rectangle(2, 3));
$figuresCollection->add(new Rectangle(3, 4));
?>
他のクラスのオブジェクトを追加しようとすると、エラーが発生します:
<?php
$figuresCollection = new FiguresCollection;
class Test {}; // 他の何らかのクラス
$figuresCollection->add(new Test); // エラーが発生します
?>
このような制御が実際に何をもたらすか:コレクションに追加されたすべての図形はインターフェース Figure を実装しているため、それぞれにメソッド getSquare とメソッド getPerimeter が確実に存在すると保証できます。
将来的に、正方形や長方形の他に、例えば三角形などが追加される可能性もあります。その場合、三角形にも同様にメソッド getSquare と getPerimeter が存在することになります。
実際には、これは次のことを可能にします:例えば、クラス FiguresCollection に、コレクション内のすべての図形の合計面積を求めるメソッド getTotalSquare を作成できます。このメソッドでは、図形の配列をループで処理し、各図形に対してメソッド getSquare を呼び出します。
各図形がインターフェース Figure を実装しているため、各図形にこのメソッド getSquare が 100% 確実に存在すると確信できます。
それでは、メソッドの実装を示します:
<?php
class FiguresCollection
{
private $figures = [];
public function addFigure(Figure $figure)
{
$this->figures[] = $figure;
}
// 合計面積を求めます:
public function getTotalSquare()
{
$sum = 0;
foreach ($this->figures as $figure) {
$sum += $figure->getSquare(); // getSquareメソッドを使用
}
return $sum;
}
}
?>
私のコードを見ずに、同じクラス FiguresCollection を実装してください。
クラス FiguresCollection に、すべての図形の合計周囲長を求めるためのメソッド getTotalPerimeter を追加してください。