リスコフ代替原理

Mar 01, 2025 am 08:47 AM

The Liskov Substitution Principle

コアポイント

  • リスコフ代替原理(LSP)は、クライアントコードで契約を破ることなく、サブクラスが基本クラスの抽象化を置き換えることができるようにするオブジェクト指向プログラミングの重要な概念です。システム設計の整合性を維持し、コードの再利用性に不可欠です。
  • サブクラスの上昇する場合、特定の要件を満たす必要があります。
  • LSP違反は、追跡が困難な止められない動作とエラーにつながる可能性があります。また、サブクラスがスーパークラスを置き換えることができるという仮定はもはや真実ではないため、コードの維持と拡張が難しくなります。
  • メソッド書き換えは、常にLSPに違反するとは限りません。ただし、書き換えられたメソッドが、スーパークラス契約では予想されない方法で元の方法の動作を変更すると、LSPに違反します。
  • コードがLSPに準拠することを確認するために、基本クラスの関数を拡張するのではなく、拡張するのではなく)サブクラスを作成することをお勧めします。さらに、継承の代わりに構成を使用してインターフェイスを実装することは、LSPによって課される条件の抽象化を破ることなく、派生クラスを作成するのに役立ちます。

架空のシーン:ハッカーとマトリックス

次の会話は、マトリックスの三部作のカットシーンから来ています:

メルフェウス:ネオ、私は今マトリックスにいます。この悪いニュースをお知らせしますが、エージェント追跡PHPプログラムには簡単な更新が必要です。現在、PDOのQuery()メソッド(文字列付き)を使用して、データベースからすべてのマトリックスエージェントの状態を取得していますが、代わりにプリプロセシングクエリを使用する必要があります。

neo:いいですね、モルフェウス。プログラムのコピーを入手できますか?

メルフェス:問題ありません。リポジトリをクローンして、agentmapper.phpおよびindex.phpファイルをチェックしてください。

(NEOはいくつかのgitコマンドを実行すると、彼の前に次のコードが表示されます)

nio:モルフェウス、文書を手に入れました。 PDOをサブクラス化し、Query()メソッドをオーバーライドして、前処理クエリを使用できるようにします。私の超大国のため、私はこの仕事を非常に迅速に終えることができるはずです。冷静さを保つ。
<?php namespace ModelMapper;

class AgentMapper
{
    protected $_adapter;
    protected $_table = "agents";

    public function __construct(PDO $adapter) {
        $this->_adapter = $adapter;
    }

    public function findAll() {
        try {
            return $this->_adapter->query("SELECT * FROM " . $this->_table, PDO::FETCH_OBJ);
        }
        catch (Exception $e) {
            return array();
        }
    }   
}
ログイン後にコピー
ログイン後にコピー
<?php use ModelMapperAgentMapper;

// 一个 PSR-0 兼容的类加载器
require_once __DIR__ . "/Autoloader.php";

$autoloader = new Autoloader();
$autoloader->register();

$adapter = new PDO("mysql:dbname=Nebuchadnezzar", "morpheus", "aa26d7c557296a4e8d49b42c8615233a3443036d");

$agentMapper = new AgentMapper($adapter);
$agents = $agentMapper->findAll();

foreach ($agents as $agent) {
    echo "Name: " . $agent->name .  " - Status: " . $agent->status . "<br>";
}
ログイン後にコピー

(コンピューターのキーボードの音が空中に響き渡ります)nio:モルフェウス、サブクラスはテストの準備ができています。いつでもチェックしてください。

(マーフィーズはラップトップで迅速に検索し、次のクラスを見ました)

メルフェス:アダプターはよく見えます。エージェントマッパーがマトリックスを通過するアクティブなエージェントを追跡できるかどうかを確認するために、すぐに試してみます。私に頑張ってください。

(Murphysはしばらくheして、以前のindex.phpファイルを実行して、今回はNeoの傑作PdoAdapterクラスを使用しています。 メルフェウス:ネオ、あなたは「救い主」だと思います!しかし、私の顔にはひどい致命的な誤りがあり、ニュースは次のとおりでした:

<?php namespace LibraryDatabase;

class PdoAdapter extends PDO
{
    protected $_statement;

    public function __construct($dsn, $username = null, $password = null, array $driverOptions = array()) {
        // 检查是否传递了有效的 DSN
        if (!is_string($dsn) || empty($dsn)) {
            throw new InvalidArgumentException("The DSN must be a non-empty string.");
        }
        try {
            // 尝试创建一个有效的 PDO 对象并设置一些属性。
            parent::__construct($dsn, $username, $password, $driverOptions);
            $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
        }
        catch (PDOException $e) {
            throw new RunTimeException($e->getMessage());
        }
    }

    public function query($sql, array $parameters = array())
    {
        try {
           $this->_statement = $this->prepare($sql);
           $this->_statement->execute($parameters);
           return $this->_statement->fetchAll(PDO::FETCH_OBJ);        
        }
        catch (PDOException $e) {
            throw new RunTimeException($e->getMessage());
        }
    }
}
ログイン後にコピー

(別の叫び声)

neo:何が問題なのですか? !何が悪かったの? ! (その他の叫び声)

メルフェス:私は本当に知りません。ああ、エージェント・スミスは今私を捕まえに来ています! (コミュニケーションが突然中断されました。長い沈黙が会話を終了し、モルフェウスが不意を突かれ、エージェントスミスによって重傷を負ったことを示唆しました。

lspは、怠zyで愚かなプログラマーを表していません

言うまでもなく、上記の対話は架空のものですが、問題は間違いなく真実です。ネオが、かつて彼がかつて有名だったハッカーのようにリスコフ代替原則(LSP)について1つか2つの知識しか学んだ場合、エージェント・スミスはすぐに追跡できました。最も重要なことは、モルフェウスはエージェントの悪意から保護されていることです。それは彼にとってとても残念でした。ただし、多くの場合、PHP開発者は、NEOの以前の意見とほぼ同じLSPについて考えています。LSPは、実際にはほとんど適用されない純粋な理論的原則に他なりません。しかし、彼らは間違った方法で行きました。 LSPの正式な定義は見事ですが(私を含む)、その中心は、同じ契約を使用する基本クラスの抽象化と子孫が非常に異なって振る舞う不明確に定義されたクラスの階層を避けることです。簡単に言えば、LSPは、サブクラスでメソッドを書き換えるとき、次の要件を満たす必要があることを規定しています。

その署名は、親クラスの署名と一致する必要があります

    前提条件(受け入れるもの)は同じか弱いか
  1. 彼らの事後条件(予想されること)は同じか強いか
  2. 例外(ある場合)は、親クラスによってスローされた例外タイプと同じでなければなりません
  3. さて、上記のリストをもう一度読んでください(心配しないでください、待ちます)。これが理にかなっている理由を理解したいと思います。例に戻ると、Neoの致命的なエラーは、メソッドの署名を同じに保つことができず、クライアントコードと契約を破ります。この問題を解決するために、エージェントマッパーのfindall()メソッドは、以下に示すように、いくつかの条件付きステートメント(明らかなコード臭)で書き直すことができます。
    <?php namespace ModelMapper;
    
    class AgentMapper
    {
        protected $_adapter;
        protected $_table = "agents";
    
        public function __construct(PDO $adapter) {
            $this->_adapter = $adapter;
        }
    
        public function findAll() {
            try {
                return $this->_adapter->query("SELECT * FROM " . $this->_table, PDO::FETCH_OBJ);
            }
            catch (Exception $e) {
                return array();
            }
        }   
    }
    ログイン後にコピー
    ログイン後にコピー

    気分が良い場合は、リファクタリング方法を試してみると、ネイティブPDOオブジェクトを使用するか、PDOアダプターのインスタンスを使用するかにかかわらず、うまく機能します。私はこれが荒いように聞こえることを知っていますが、それは迅速かつ簡単な修正であり、開閉の原則に露骨に違反しています。一方、AdapterのQuery()メソッドは、親クラスの書き換えの署名に一致するようにリファクタリングできます。しかし、そうすることで、LSPによって記載されている他のすべての条件も満たされるべきです。要するに、これは、メソッドの書き換えは注意して行うべきであり、非常に強い理由でのみ行うことができることを意味します。多くのユースケースでは、インターフェイスを使用できないと仮定すると、基本クラスの機能を(オーバーライドするのではなく)拡張するだけのサブクラスを作成する方が良いです。 NEOのPDOアダプターの場合、このアプローチは完全に機能し、クライアントコードをどのレベルでも破ることはありません。先ほど言ったように、インターフェイスの実装を活用するより効率的な、しかしより根本的なソリューションがあります。以前のPDOアダプターは継承を通じて作成され、LSPの教訓に間違いなく違反しましたが、実際には、エージェントマッパークラスが元々設計された方法から欠点があります。実際、インターフェイス定義の契約ではなく、具体的なデータベースアダプターの実装に依存します。そして、古代から大きなOO力が言われてきましたが、これは常に悪いことです。では、上記のソリューションはどのように実装されますか?

    (残りは入力テキストに似ており、必要に応じて調整および簡素化できます)

以上がリスコフ代替原理の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、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衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

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

SublimeText3 中国語版

SublimeText3 中国語版

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

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

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

PHPのカール:REST APIでPHPカール拡張機能を使用する方法 PHPのカール:REST APIでPHPカール拡張機能を使用する方法 Mar 14, 2025 am 11:42 AM

PHPクライアントURL(CURL)拡張機能は、開発者にとって強力なツールであり、リモートサーバーやREST APIとのシームレスな対話を可能にします。尊敬されるマルチプロトコルファイル転送ライブラリであるLibcurlを活用することにより、PHP Curlは効率的なexecuを促進します

Codecanyonで12の最高のPHPチャットスクリプト Codecanyonで12の最高のPHPチャットスクリプト Mar 13, 2025 pm 12:08 PM

顧客の最も差し迫った問題にリアルタイムでインスタントソリューションを提供したいですか? ライブチャットを使用すると、顧客とのリアルタイムな会話を行い、すぐに問題を解決できます。それはあなたがあなたのカスタムにより速いサービスを提供することを可能にします

PHPにおける後期静的結合の概念を説明します。 PHPにおける後期静的結合の概念を説明します。 Mar 21, 2025 pm 01:33 PM

記事では、PHP 5.3で導入されたPHPの後期静的結合(LSB)について説明し、より柔軟な継承を求める静的メソッドコールのランタイム解像度を可能にします。 LSBの実用的なアプリケーションと潜在的なパフォーマ

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.パフォーマンスの最適化とベストプラクティスには、適切な署名アルゴリズムの使用、有効期間を合理的に設定することが含まれます。

フレームワークセキュリティ機能:脆弱性から保護します。 フレームワークセキュリティ機能:脆弱性から保護します。 Mar 28, 2025 pm 05:11 PM

記事では、入力検証、認証、定期的な更新など、脆弱性から保護するためのフレームワークの重要なセキュリティ機能について説明します。

フレームワークのカスタマイズ/拡張:カスタム機能を追加する方法。 フレームワークのカスタマイズ/拡張:カスタム機能を追加する方法。 Mar 28, 2025 pm 05:12 PM

この記事では、フレームワークにカスタム機能を追加し、アーキテクチャの理解、拡張ポイントの識別、統合とデバッグのベストプラクティスに焦点を当てています。

PHPのCurlライブラリを使用してJSONデータを含むPOSTリクエストを送信する方法は? PHPのCurlライブラリを使用してJSONデータを含むPOSTリクエストを送信する方法は? Apr 01, 2025 pm 03:12 PM

PHP開発でPHPのCurlライブラリを使用してJSONデータを送信すると、外部APIと対話する必要があることがよくあります。一般的な方法の1つは、Curlライブラリを使用して投稿を送信することです。

See all articles