PHP Manual

PPEにおける封止の原理

16. 02. 2020

OOPの主要な原則のひとつに**カプセル化原則**があります。これは、複雑な問題は、独立して同時に解決できる多くの小さな問題に分解されるべきであるというものです。同時に、私たちユーザーは、それがどのように起こるかを気にせず、データ(内部状態)は分離されたままです。

例えば、(5+3)*(2/(7+3)) という式のユーザークエリに基づいて、どのように結果 1.6 を返すかという問題を解く場合、おそらく誰もこの問題を一度に解決する単一の関数やメソッドを書くことはできないでしょう。

HINT: この種の例に対する既製の解決策は、記事文字列としての数式処理にありますが、簡単ではないことを覚悟しておいてください。

カプセル化によりオブジェクトを抽象化

カプセル化すれば、オブジェクトを「ユーザーとして」使うことができるようになります。つまり、オブジェクトのメソッドを呼び出すだけで、オブジェクトが内部でどのように動作しているかをまったく気にする必要がなくなるのです。

例えば、従業員の給与計算を行う場合、他のプログラマーが作成した既存のクラスを利用して計算を行いたいとします。コンストラクタの必須パラメータを知るだけで、そのクラスを「ただ使う」ことができるのです。

$mzda = new MzdaZamestnance(
25000, // 総支給額
6, // 入社年数
10, // 経験年数
true // 男なのか?
);
echo $mzda->getHruba(); // 25000
echo $mzda->getCista(); // 17800

オブジェクトのパラメータは架空のものであり、賃金の計算方法と現実的に対応するものではありません。特に、この原理は、一般に公開されているインターフェースだけを知っていればよく、オブジェクトの内部状態内部実装、さらにはなぜそれがそのように動作するのかを扱う必要さえないという事実によって示される。単純に getCista() メソッドを呼び出して、純益を得るだけです。

カプセル化は設計上の問題

注意すべきは、カプセル化自体は、言語の機能や構文ではないということです。クラスやアプリケーションがカプセル化されているということは、プログラマがアプリケーションを設計し、コードを考えているに過ぎないのです。

クラスデザインは常にこう考えています。

  • KISS(keep it simple)、インターフェイスをシンプルにし、ユーザーに不必要な思考を強いないことです。複雑なロジックを解決してあげれば、ユーザーに感謝されるはずです。
  • クラスの利用者(他のプログラマや未来のあなた)は、内部ロジックを知る必要は全くなく、メソッド名とそのパラメータだけで十分なはずです。
  • ユーザーにとって興味のない、技術的なことだけを考えた計算の補助的な計算が必要な場合、そのゲッターを作る意味は全くなく、内部で計算するのみであるべきです。
  • このクラスはアルゴリズムの基本的な特性、特にどのようなデータに対しても一般的に動作することを満たさなければなりません。
  • 公開されているメソッドは、将来的に新しい機能でオブジェクトを拡張するのに十分な情報を提供し、すでに知っていることから新しいデータを簡単に計算できるように設計されている必要があります。

社内データの非開示

内部ロジックを処理するプロパティやメソッドについては、可視性を private に設定することが理にかなっています。その最大のメリットは、外部から呼び出されることがなく、ユーザーは自分の設計したインターフェースを使わざるを得ないので、データやオブジェクトの内部状態を保護することができることです。

例えば、銀行口座を表すオブジェクトがあり、支払の計上と現在の残高を処理したいとします。

class BankAccount
{
private int $sum;
public function __construct(int $startSum)
{
$this->sum = $startSum >= 0 ? $startSum : 0;
}
public function getSum(): int
{
return $this->sum;
}
public function pay(int $price): void
{
$newSum = $this->sum - $price;
if ($newSum < 0) {
throw new \Exception('そんなお金ないでしょ!?');
}
$this->sum = $newSum;
}
public function addMoney(int $money): void
{
$this->sum += $money;
}
}

このクラスには、現在の残高を格納する $sum という private プロパティがひとつだけ含まれていることに注意してください。

現在の残高を取得したい場合は、getSum() メソッドがありますが、新しい残高の値を変更する方法がありません。お金を取り除くには pay() メソッドを、お金を加えるには addMoney() メソッドを使うしかありません。

この原則のおかげで、私たちは常に、誰もその物体を壊すことができないことを確実に知ることができるのです。

もしユーザーが口座に実際にある以上の金額を支払おうとすると、pay()メソッドはそれを許しません。なぜなら、$sumプロパティを上書きする前にチェック計算を行い、もし残高がマイナス(0未満)になるはずなら、エラー例外を投げて処理を停止するからです。

結論

カプセル化の基本原理を示したことで、オブジェクトの抽象化についてよりよく考えることができ、まったく新しい視点がもたらされました。

いったんこの原則をよく理解すれば、フレームワークが非常に多くの意味を持ち始めることがわかるでしょう、なぜなら、フレームワークは内部で多くの賢さをカプセル化しており、それを利用するだけでよいからです。

次回は、dedicacy and visibilityについて見ていきます。

Jan Barášek   Více o autorovi

Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.

Rád vám pomůžu:

Související články

1.
7.
Status:
All systems normal.
2024