目次
省略形は
接口隔离原则
依赖倒置原则
总结
ホームページ 見出し PHP におけるオブジェクト指向設計の 5 つの基本原則

PHP におけるオブジェクト指向設計の 5 つの基本原則

Jun 12, 2019 pm 05:54 PM
php オブジェクト指向

PHP におけるオブジェクト指向設計の 5 つの基本原則

S.O.L.I.D5 つのオブジェクト指向設計のうちの最初のものです(OOD)Principles の頭字語であるこれらの原則は、Uncle Bob として知られる Robert C. Martin によって提案されました。

これらのガイドラインにより、スケーラブルで保守可能なソフトウェアの開発が容易になります。また、コードがより合理化され、リファクタリングが容易になります。アジャイル開発と適応型ソフトウェア開発の一部でもあります。

: これは「__S.O.L.I.Dへようこそ」への単純な紹介ではなく、この記事は明確にしたいと考えています S.O.L.I.D どういうことですか。 (関連チュートリアルの推奨事項: php ビデオ チュートリアル)

S.O.L.I.D の意味:

展開された頭字語は複雑に見えるかもしれませんが、実際には非常に簡単に理解できます。

  • S - 単機能原理
  • #O - 開閉原理
  • #L - Liskov 置換原則
  • #I
  • - インターフェース分離原則
  • #D
  • - 依存関係逆転原則
  • #次は見てみましょうそれぞれの原則について、なぜ S.O.L.I.D が私たちがより良い開発者になるのに役立つのかを理解してください。

単一責任の原則

省略形は

S.R.P

です。この原則の内容は次のとおりです:

クラスには 1 つの責任しかありません。それは、クラスが 1 つの責任だけを持つべきであることを意味します。

たとえば、いくつかの形状があり、これらの形状の合計面積を計算したいとします。はい、簡単ですよね?
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

クラス、特に sum メソッドを見てみましょう。

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);
}
ログイン後にコピー

sum

メソッドを使用してさらに多くの図形の面積を計算したい場合は、さらに if/else ブロック を追加する必要がありますが、これは違反です開閉原理。 この

sum

メソッドをより良くする方法は、各図形の面積を計算するコード ロジックを sum メソッドから移動し、それを各図形クラスに入れることです。

class Square {
    public $length;

    public function __construct($length) {
        $this->length = $length;
    }

    public function area() {
        return pow($this->length, 2);
    }
}
ログイン後にコピー
同じ操作を使用して

Circle

クラスを処理し、クラスに area メソッドを追加する必要があります。これで、任意の形状の面積の合計の計算は次のように簡単になります。

public function sum() {
    foreach($this->shapes as $shape) {
        $area[] = $shape->area();
    }

    return array_sum($area);
}
ログイン後にコピー
次に、別の形状クラスを作成し、コードを中断することなく合計を計算するときにそれを渡すことができます。しかし、ここで別の疑問が生じます。

AreaCalculator

に渡されたオブジェクトが実際に形状であること、または形状オブジェクトに area メソッドが存在することをどのようにして知ることができるのでしょうか。 インターフェイス コーディングは、

S.O.L.I.D

の実践の一部です。たとえば、次の例ではインターフェイス クラスを作成し、各シェイプ クラスがこのインターフェイス クラスを実装します:

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

の sum メソッドでは、提供された形状クラスのインスタンスが 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 に型 T2 のオブジェクト o2 が存在する場合、T1 で定義されたすべてのプログラム P はすべてのオブジェクト o1 で o2 に置き換えられます。プログラム 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 AreaCalculator($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 类的 sum 方法返回数组。

$summedData 是一个浮点数、双精度浮点数或者整型。

接口隔离原则

使用方(client)不应该依赖强制实现不使用的接口,或不应该依赖不使用的方法。

继续使用上面的 shapes 例子,已知拥有一个实心块,如果我们需要计算形状的体积,我们可以在 ShapeInterface 中添加一个方法:

interface ShapeInterface {
    public function area();
    public function volume();
}
ログイン後にコピー

任何形状创建的时候必须实现 volume 方法,但是【平面】是没有体积的,实现这个接口会强制的让【平面】类去实现一个自己用不到的方法。

ISP 原则不允许这么去做,所以我们应该创建另外一个拥有 volume 方法的SolidShapeInterface 接口去代替这种方式,这样类似立方体的实心体就可以实现这个接口了:

interface ShapeInterface {
    public function area();
}

interface SolidShapeInterface {
    public function volume();
}

class Cuboid implements ShapeInterface, SolidShapeInterface {
    public function area() {
        //计算长方体的表面积
    }

    public function volume() {
        // 计算长方体的体积
    }
}
ログイン後にコピー

这是一个更好的方式,但是要注意提示类型时不要仅仅提示一个 ShapeInterfaceSolidShapeInterface
你能创建其它的接口,比如 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 类中,我们可以很容易地用 calculate替换对area 方法的调用,并检查对象是否是 ManageShapeInterface 的实例,而不是 ShapeInterface

依赖倒置原则

最后,但绝不是最不重要的:

实体必须依赖抽象而不是具体的实现.即高等级模块不应该依赖低等级模块,他们都应该依赖抽象.

这也许听起来让人头大,但是它很容易理解.这个原则能够很好的解耦,举个例子似乎是解释这个原则最好的方法:

class PasswordReminder {
    private $dbConnection;

    public function __construct(MySQLConnection $dbConnection) {
        $this->dbConnection = $dbConnection;
    }
}
ログイン後にコピー

首先 MySQLConnection 是低等级模块,然而 PasswordReminder 是高等级模块,但是根据 S.O.L.I.D. 中 D 的解释:依赖于抽象而不依赖与实现, 上面的代码段违背了这一原则,因为 PasswordReminder 类被强制依赖于 MySQLConnection 类.

稍后,如果你希望修改数据库驱动,你也不得不修改 PasswordReminder 类,因此就违背了 Open-close principle

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;
    }
}
ログイン後にコピー

从上面一小段代码,你现在能看出高等级和低等级模块都依赖于抽象了。

总结

说实话,S.O.L.I.D 一开始似乎很难掌握,但只要不断地使用和遵守其原则,它将成为你的一部分,使你的代码易被扩展、修改,测试,即使重构也不容易出现问题。

相关PHP面向对象视频教程推荐:《PHP面向对象视频教程》

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Ubuntu および Debian 用の PHP 8.4 インストールおよびアップグレード ガイド Ubuntu および Debian 用の PHP 8.4 インストールおよびアップグレード ガイド Dec 24, 2024 pm 04:42 PM

PHP 8.4 では、いくつかの新機能、セキュリティの改善、パフォーマンスの改善が行われ、かなりの量の機能の非推奨と削除が行われています。 このガイドでは、Ubuntu、Debian、またはその派生版に PHP 8.4 をインストールする方法、または PHP 8.4 にアップグレードする方法について説明します。

今まで知らなかったことを後悔している 7 つの PHP 関数 今まで知らなかったことを後悔している 7 つの PHP 関数 Nov 13, 2024 am 09:42 AM

あなたが経験豊富な PHP 開発者であれば、すでにそこにいて、すでにそれを行っていると感じているかもしれません。あなたは、運用を達成するために、かなりの数のアプリケーションを開発し、数百万行のコードをデバッグし、大量のスクリプトを微調整してきました。

PHP 開発用に Visual Studio Code (VS Code) をセットアップする方法 PHP 開発用に Visual Studio Code (VS Code) をセットアップする方法 Dec 20, 2024 am 11:31 AM

Visual Studio Code (VS Code とも呼ばれる) は、すべての主要なオペレーティング システムで利用できる無料のソース コード エディター (統合開発環境 (IDE)) です。 多くのプログラミング言語の拡張機能の大規模なコレクションを備えた VS Code は、

JSON Web Tokens(JWT)とPHP APIでのユースケースを説明してください。 JSON Web Tokens(JWT)とPHP APIでのユースケースを説明してください。 Apr 05, 2025 am 12:04 AM

JWTは、JSONに基づくオープン標準であり、主にアイデンティティ認証と情報交換のために、当事者間で情報を安全に送信するために使用されます。 1。JWTは、ヘッダー、ペイロード、署名の3つの部分で構成されています。 2。JWTの実用的な原則には、JWTの生成、JWTの検証、ペイロードの解析という3つのステップが含まれます。 3. PHPでの認証にJWTを使用する場合、JWTを生成および検証でき、ユーザーの役割と許可情報を高度な使用に含めることができます。 4.一般的なエラーには、署名検証障害、トークンの有効期限、およびペイロードが大きくなります。デバッグスキルには、デバッグツールの使用とロギングが含まれます。 5.パフォーマンスの最適化とベストプラクティスには、適切な署名アルゴリズムの使用、有効期間を合理的に設定することが含まれます。

PHPでHTML/XMLを解析および処理するにはどうすればよいですか? PHPでHTML/XMLを解析および処理するにはどうすればよいですか? Feb 07, 2025 am 11:57 AM

このチュートリアルでは、PHPを使用してXMLドキュメントを効率的に処理する方法を示しています。 XML(拡張可能なマークアップ言語)は、人間の読みやすさとマシン解析の両方に合わせて設計された多用途のテキストベースのマークアップ言語です。一般的にデータストレージに使用されます

母音を文字列にカウントするPHPプログラム 母音を文字列にカウントするPHPプログラム Feb 07, 2025 pm 12:12 PM

文字列は、文字、数字、シンボルを含む一連の文字です。このチュートリアルでは、さまざまな方法を使用してPHPの特定の文字列内の母音の数を計算する方法を学びます。英語の母音は、a、e、i、o、u、そしてそれらは大文字または小文字である可能性があります。 母音とは何ですか? 母音は、特定の発音を表すアルファベットのある文字です。大文字と小文字など、英語には5つの母音があります。 a、e、i、o、u 例1 入力:string = "tutorialspoint" 出力:6 説明する 文字列「TutorialSpoint」の母音は、u、o、i、a、o、iです。合計で6元があります

PHPでの後期静的結合を説明します(静的::)。 PHPでの後期静的結合を説明します(静的::)。 Apr 03, 2025 am 12:04 AM

静的結合(静的::) PHPで後期静的結合(LSB)を実装し、クラスを定義するのではなく、静的コンテキストで呼び出しクラスを参照できるようにします。 1)解析プロセスは実行時に実行されます。2)継承関係のコールクラスを検索します。3)パフォーマンスオーバーヘッドをもたらす可能性があります。

PHPマジックメソッド(__construct、__destruct、__call、__get、__setなど)とは何ですか? PHPマジックメソッド(__construct、__destruct、__call、__get、__setなど)とは何ですか? Apr 03, 2025 am 12:03 AM

PHPの魔法の方法は何ですか? PHPの魔法の方法には次のものが含まれます。1。\ _ \ _コンストラクト、オブジェクトの初期化に使用されます。 2。\ _ \ _リソースのクリーンアップに使用される破壊。 3。\ _ \ _呼び出し、存在しないメソッド呼び出しを処理します。 4。\ _ \ _ get、dynamic属性アクセスを実装します。 5。\ _ \ _セット、動的属性設定を実装します。これらの方法は、特定の状況で自動的に呼び出され、コードの柔軟性と効率を向上させます。