PHP

PHP基礎(12)カプセル化


アクセサメソッド

インスタンス変数を読み書きするためのメソッドをアクセサメソッドと言います。(値をセットするセッターと、値をゲットするゲッターという2つのメソッドの総称です)

例として以下のコードを考えます。四角の縦(height)、横(width)を管理するクラスです。

<?php

/* 四角クラス */
class Square {
/* 縦 */
private $height;
/* 横 */
private $width;
function __construct($height,$width) {
$this->height = $height;
$this->width = $width;
}
/* 縦setter */
function setHeight($height) {
$this->height = $height;
}
/* 縦getter */
function getHeight() {
return $this->height;
}
/* 横setter */
function setWidth($width) {
$this->width = $width;
}
/* 横getter */
function getWidth() {
return $this->width;
}

/* 面積計算 */
function calcArea() {
return $this->height * $this->width;
}
/* 正方形か? */
function isSquare() {
if ($this->height == $this->width) {
return true;
} else {
return false;
}
}
}

//呼び出し
$sq = new Square(40,20);
$area = $sq->calcArea();
echo "area = $area ";// => 800
//正方形か否か
$b = $sq->isSquare();
var_dump($b);// => false
//縦を変更
$sq->setHeight(20);
$area = $sq->calcArea();
echo "area = $area ";// => 400
//正方形か否か
$b = $sq->isSquare();
var_dump($b);// => true
?>

縦(height)、横(width)のインスタンス変数をセットするセッターメソッドとゲットするゲッターメソッドがそれぞれあります。そして面積計算メソッド(calcArea)と、正方形か否かを判定するメソッド(isSquare)が内部でインスタンス変数を使って面積計算したり、縦と横の比較を行なっています。

つまりオブジェクトはメソッド呼び出しが外と繋がる手段になっています。

このようにインスタンス内部で持っている値(privateなインスタンス変数)に触ることができるメソッドは、オブジェクトの言わば出入口です。オブジェクトは薬の粉を包むカプセルのようなイメージですので、これらメソッドはオブジェクトの内と外の世界を繋げる細いトンネルのような物です。


カプセル化

オブジェクト指向のカプセル化の概念はこのトンネル(メソッド)を使ってオブジェクトを操作させよう、と考えることです。

カプセル化を適切に考えると、オブジェクト同士の紐付き(関係性)を薄くし、独立性を高め、再利用や交換といった保守性を高めることになります。

プログラムは常に改善、改造を繰り返し、より良いものになって行きます。その作業を行うプログラマーは、一人とは限りません。多くの人が関係します。また、時間経過が長く、作ったものを忘れてしまうときもあります。そういう人のたずさわるプログラムにミスやバグが入り込まないようにすることが目的です。

上記のコードはクラスを使う側から考えたときに依存度は最小限です。インスタンス化のときに縦、横の数値を渡し、必要に応じて縦、横の数値をセッターで変更し、各メソッドを呼び出せば計算値が受け取れます。

もしこれをアクセサメソッドを使わずに書くとどうなるでしょうか。

<?php

/* 四角クラス */
class Square2 {
/* 面積計算 */
function calcArea($height,$width) {
return $height * $width;
}
/* 正方形か? */
function isSquare($height,$width) {
if ($height == $width) {
return true;
} else {
return false;
}
}
}

//呼び出し
$sq = new Square2();
$area = $sq->calcArea(40,20);
echo "area = $area ";
//正方形か否か
$b = $sq->isSquare(40,20);
var_dump($b);
//縦を変更
$area = $sq->calcArea(20,20);
echo "area = $area ";
//正方形か否か
$b = $sq->isSquare(20,20);
var_dump($b);
?>

コンストラクタは不要になり、各メソッドの呼び出しで引数として縦、横の数値を渡すことになります。

このクラスSquare2を使う側はインスタンス化は1箇所で行うとして、各メソッドが色々なところから呼ばれるコードになっているとするとメソッドの引数の数値2つは冗長です。いつも縦、横の数値が必要になります。縦、横の数値管理の役目がSquare2には無くなります。

さて、もしこの縦、横の数値管理の役目がないインスタンス変数を持たない四角クラスSquare2を、立体も扱うように改造しようとする必要が出てきたとき、奥行(depth)という変数を各メソッドの引数に加える必要があり、メソッドの呼び出し箇所を一斉に変更する必要が出てきます。呼び出し側では縦、横、奥行きの3値を管理する必要が出てきます。

しかし、最初に紹介したクラスSquareの場合での改造は、インスタンス変数に奥行(depth)を追加し、各メソッド内でその値を内部で使い演算方法を修正すればいいだけになります。(もちろんメソッド名に変更はないということが前提ですが)

このようにいろんな箇所から呼ばれることを想定し、仕様変更があったとしても構造的な影響が最小限になるよう考えてそのオブジェクトの管理すべきデータ、操作する内容を適切な所属や扱い方にしておくことが、つまりは結果的にオブジェクトを疎結合にすることになります。

<<PHP基礎(11)変数たち

PHP基礎(13)ポリモーフィズム>>