SOLIDは、最初の5人のイニシャルオブジェクト指向設計(OOD)ガイドラインの略語、ロバートC.マーティンによって提案されたガイドラインである、彼は良く知られている名前がありましたおじさんボブ。
これらのガイドラインは、簡単にスケーラブルな、保守性ソフトウェアの開発を行います。また簡単に再構成された、コードをよりコンパクトになります。アジャイル開発とは、適応ソフトウェア開発の一部です。
SOLID手段:
アウト拡張頭字語は、実際には、彼らが理解しやすい、複雑に見えるかもしれません。
- S -単一責任の原則
- O -オープンクローズドの原則
- L -リヒターの置換原則
- I -インターフェイス分掌の原則
- D -依存関係逆転の原則
理由を理解するために、各原則を見てみましょうSOLIDは、私たちはより良い開発者になることができます。
単一責任の原則
略称SRP、原理は読み取ります。
クラスは、クラスは単一の責任を持つべきであることを意味し、変更を加えることで、唯一の要因があります。
例えば、我々はいくつかのグラフィックスを持っており、あなたがこれらのグラフィックスの総面積を計算するとします。はい、それは右、非常に単純なのですか?
class Circle {
public $radius;
public function construct($radius) {
$this->radius = $radius;
}
}
class Square {
public $length;
public function construct($length) {
$this->length = $length;
}
}
まず、必要なパラメータを初期化するために、グラフィックスクラス、クラスのコンストラクタを作成します。次に、作成AreaCalculatorのクラスを、その後、ロジックコードの総面積を計算する特定のパターンを書き込みます。
class AreaCalculator {
protected $shapes;
public function __construct($shapes = array()) {
$this->shapes = $shapes;
}
public function sum() {
// logic to sum the areas
}
public function output() {
return implode('', array(
"",
"Sum of the areas of provided shapes: ",
$this->sum(),
""
));
}
}
AreaCalculatorの使用、我々は単にクラスをインスタンス化し、グラフィックス、ページの表示出力の一番下にあるコンテンツの配列を渡します。
$shapes = array(
new Circle(2),
new Square(5),
new Square(6)
);
$areas = new AreaCalculator($shapes);
echo $areas->output();
問題の出力方法、そのAreaCalculator処理されたデータの出力論理。そのため、ユーザーがにデータを望んでいる場合は、JSONまたは他の出力形式、それ?
すべてのロジックAreaCalculatorの正確単一責任(の原則に違反しているクラスの治療、SRP); AreaCalculatorのクラスは、グラフィックスの総面積の計算を担当する必要があり、それは心配するべきではありませんが、ユーザーがしたいですJSONまたはHTML形式のデータを。
したがって、この問題を解決するために、あなたが作成することができSumCalculatorOutputterのクラスを、および表示する方法の総面積のすべてのグラフィックスを処理するために必要なロジック処理を表示するためにそれを使用します。
SumCalculatorOutputterの次のような作業のカテゴリは次のとおりです。
$shapes = array(
new Circle(2),
new Square(5),
new Square(6)
);
$areas = new AreaCalculator($shapes);
$output = new SumCalculatorOutputter($areas);
echo $output->JSON();
echo $output->HAML();
echo $output->HTML();
echo $output->JADE();
今、どんなにあなたがによって、ユーザーにデータを出力したいどのような形式SumCalculatorOutputterのクラス処理。
オープンクローズ原理
オブジェクトとエンティティは、拡張のために開いているが、修正のために閉鎖すべきです。
簡単に言えば、クラスは簡単にその機能を拡張することができ、自分のを変更する必要はありません。のは、見てみましょうAreaCalculatorのクラス、特に和方法。
public function sum() {
foreach($this->shapes as $shape) {
if(is_a($shape, 'Square')) {
$area[] = pow($shape->length, 2);
} else if(is_a($shape, 'Circle')) {
$area[] = pi() * pow($shape->radius, 2);
}
}
return array_sum($area);
}
私たちが使用したい場合は合計面積は、より多くのグラフィック計算できる方法を、我々はより多くを追加する必要があり、他/ IFが、開閉の原則に反します。
ましょう和プロセスは、より良い方法は、のうちの各形状コードロジックの面積を計算することであるとなり和様々なクラスに成形される方法であって、
class Square {
public $length;
public function __construct($length) {
$this->length = $length;
}
public function area() {
return pow($this->length, 2);
}
}
同様の操作を処理するために使用されるべきサークル、クラスにクラスを追加領域方法。さて、任意の形状の面積を計算し、次のように簡単でなければなりません。
public function sum() {
foreach($this->shapes as $shape) {
$area[] = $shape->area();
}
return array_sum($area);
}
次は他の形状クラスを作成し、我々のコードを破壊することなく総和を計算する際にそれを渡すことができます。しかし、今、別の問題があり、どのように我々は、着信を知ることができるAreaCalculatorオブジェクトが実際に形で、またはオブジェクトの形状が持つエリア方法を?
実際のコーディングインターフェイスSOLID例えば、我々はインターフェイスクラスを作成するには、次の例を一部を、各クラスの形状は、このインタフェースクラスを実装します。
interface ShapeInterface {
public function area();
}
class Circle implements ShapeInterface {
public $radius;
public function __construct($radius) {
$this->radius = $radius;
}
public function area() {
return pi() * pow($this->radius, 2);
}
}
当社ではAreaCalculator 和法、我々がいるかどうか、クラスの形状によって提供されている例を調べることができますShapeInterfaceは、そうでない場合、我々は例外がスローされます、達成を:
public function sum() {
foreach($this->shapes as $shape) {
if(is_a($shape, 'ShapeInterface')) {
$area[] = $shape->area();
continue;
}
throw new AreaCalculatorInvalidShapeException;
}
return array_sum($area);
}
リヒターの置換原則
T1 O1のそれぞれのオブジェクトタイプ、O2 T2は、オブジェクトタイプを持っている場合、すべての世代がオブジェクトをO1、O2を置き換えた場合、全てのP T1プログラムを定義するように、プログラムPの挙動は、次に型を変更されていませんT2は、T1型のサブタイプです。
各サブクラスまたは派生クラスが問題/親クラスなしで基本クラスを置き換えることができます:フレーズの定義があることを意味します。
まだ使用AreaCalculatorのクラスを、私たちは持っていると仮定しVolumeCalculatorの継承クラスAreaCalculatorのカテゴリを:
class VolumeCalculator extends AreaCalulator {
public function construct($shapes = array()) {
parent::construct($shapes);
}
public function sum() {
// logic to calculate the volumes and then return and array of output
return array($summedData);
}
}
SumCalculatorOutputterのカテゴリ:
class SumCalculatorOutputter {
protected $calculator;
public function __constructor(AreaCalculator $calculator) {
$this->calculator = $calculator;
}
public function JSON() {
$data = array(
'sum' => $this->calculator->sum();
);
return json_encode($data);
}
public function HTML() {
return implode('', array(
'',
'Sum of the areas of provided shapes: ',
$this->calculator->sum(),
''
));
}
}
我々はこのような例を実行する場合:
$areas = new AreaCalculator($shapes);
$volumes = new VolumeCalculator($solidShapes);
$output = new SumCalculatorOutputter($areas);
$output2 = new SumCalculatorOutputter($volumes);
プログラムが間違って行くことはありませんが、我々は、使用時に$ OUTPUT2呼び出すためにオブジェクトをHTMLの方法は、私たちが受け取ったときにE_NOTICEを我々が使用されるエラー文字列の配列として扱われることを示唆し、エラーを。
単純に、この問題を解決するには:
public function sum() {
// logic to calculate the volumes and then return and array of output
return $summedData;
}
よりむしろVolumeCalculatorクラス和方法アレイを返します。
$ summedDataは浮動小数点、倍精度浮動小数点または整数です。
インターフェイスの棲み分け原理
消費者(クライアント)インタフェースの使用に頼るべきではありませんが施行されていない、この方法は、使用中のかを頼るべきではありません。
上記の継続的な使用形状知られている例では、我々は形状の体積を計算する必要がある場合、我々ができ、固体ブロックを有するShapeInterface一つの方法を追加します。
interface ShapeInterface {
public function area();
public function volume();
}
作成した任意の時間は、形状ボリュームのメソッドを実装する必要がありますが、「飛行機」は何のボリュームではありません、このインタフェースの実装は、「飛行機」クラスは、独自未満メソッドを実装するために作ることを余儀なくされます。
ISPの原則がそうすることはできませんので、我々は別の作成する必要がありますボリューム方式SolidShapeInterfaceのこの方法を置き換えるためのインタフェースを、このインタフェースを実装することができ、この立方体のようなソリッドボディ:
interface ShapeInterface {
public function area();
}
interface SolidShapeInterface {
public function volume();
}
class Cuboid implements ShapeInterface, SolidShapeInterface {
public function area() {
//计算长方体的表面积
}
public function volume() {
// 计算长方体的体积
}
}
これは良い方法ですが、プロンプトを入力するように求められない場合にのみ、注意してくださいShapeInterfaceまたはSolidShapeInterfaceを。
あなたのような他のインターフェースを作成することができManageShapeInterfaceを、あなたは簡単に管理するためのフォームがあることがわかりますので、飛行機やクラスの立方体でそれを実装するAPIが。例:
interface ManageShapeInterface {
public function calculate();
}
class Square implements ShapeInterface, ManageShapeInterface {
public function area() { /Do stuff here/ }
public function calculate() {
return $this->area();
}
}
class Cuboid implements ShapeInterface, SolidShapeInterface, ManageShapeInterface {
public function area() { /Do stuff here/ }
public function volume() { /Do stuff here/ }
public function calculate() {
return $this->area() + $this->volume();
}
}
今でAreaCalculatorのクラスは、我々は簡単に使用できる計算に代わるものをエリアと呼ばれる方法、およびオブジェクトがあるかどうかを確認ManageShapeInterfaceの代わりに、インスタンスShapeInterface。
依存関係逆転の原則
最後に、ではなく、少なくとも:
エンティティは抽象的ではなく、具体的な実装に依存しなければなりません。そのハイレベルのモジュールは、低レベルのモジュールに依存してはならない、彼らは抽象的に依存している必要があります。
聞こえることがありますが、これは大きな頭になりますが、理解しやすいです。この原則はうまく切り離すことができ、例えば、この原理を説明するための最良の方法であると思われます。
class PasswordReminder {
private $dbConnection;
public function __construct(MySQLConnection $dbConnection) {
$this->dbConnection = $dbConnection;
}
}
最初MySqlConnectionにローレベルのモジュール、PasswordReminder高品位のモジュールが、係る固体でDは説明:実装に依存せず抽象に依存するため、上記のコードは、この原理に反しスニペットPasswordReminderのクラスがに頼ることを余儀なくされるMySqlConnectionにするクラス。
あなたがデータベースドライバを変更したい場合は、後で、あなたは変更する必要がPasswordReminderクラスを、それゆえに反し開口部と原則(オープン-使用閉じる原理)を閉じます。
このPasswordReminderのクラスは、我々はインターフェイスを作成することができ、抽象化に依存しなければならないため、高品位かつ低品位モジュールに、我々 「コードを書くためのインターフェース」アプリケーションは、さらにこの問題に対処するために、データベースを使用して何を心配すべきではありません。
interface DBConnectionInterface {
public function connect();
}
このインタフェースは、データベースに接続する方法があり、MySqlConnectionには、このインタフェースを実装するクラスは、中PasswordReminderの工法直接に制約を入力しないMySqlConnectionにするクラスが、クラスがインターフェイスに設定されているので、データベースアプリケーションの何があっあなたのタイプ、PasswordReminderクラスは何の問題もなく、とから逸脱することなく、データベースに接続することができ、シャッター原則。
class MySQLConnection implements DBConnectionInterface {
public function connect() {
return "Database connection";
}
}
class PasswordReminder {
private $dbConnection;
public function __construct(DBConnectionInterface $dbConnection) {
$this->dbConnection = $dbConnection;
}
}
上記のコード片から、あなたは今、高品位かつ低学年のモジュールは抽象的に依存している見ることができます。
概要
正直に言うと、SOLIDは、最初に把握するのが難しいようですが、限り、その原則に一定の使用やコンプライアンスとして、それはあなたのコードを簡単に再構築が問題になりやすいでなくても、テストを拡張、変更するために、あなたの一部となります。