ホームページ  >  記事  >  バックエンド開発  >  PHP デザイン パターンのプロキシ パターンを 1 つの記事で理解する

PHP デザイン パターンのプロキシ パターンを 1 つの記事で理解する

齐天大圣
齐天大圣オリジナル
2020-07-31 16:59:002355ブラウズ

プロキシ パターンは、クラスとオブジェクトが組み合わされる古典的な構造を対象とした構造設計パターンです。プロキシ パターンも頻繁に使用されるデザイン パターンであり、ターゲット オブジェクトを変更せずに機能を追加できるため、注目が必要です。

定義

プロキシ モード (プロキシ) は、このオブジェクトへのアクセスを制御するために他のオブジェクトにプロキシを提供します。プロキシ パターンを使用してプロキシ オブジェクトを作成し、そのプロキシ オブジェクトにターゲット オブジェクトへのアクセスを制御させます (ターゲット オブジェクトは、リモート オブジェクト、作成にコストがかかるオブジェクト、またはセキュリティ制御が必要なオブジェクトである可能性があります)。ターゲットオブジェクトの機能を変更せずに、いくつかのエクストラを追加します。

質問

現在、システムにはユーザーのログインおよび登録業務用の Login クラスがあります。疑似コードは次のとおりです。

class UserLogin
{
    // …… 省略属性和部分方法
    
    public function login ($name, $pass)
    {
        // 登录业务
    }
    
    public function reg ($name, $pass)
    {
        // 注册业务
    }
}

次に、ユーザーのログインおよび登録ビジネスに関数を追加します。これにより、クライアントはこのメソッドの呼び出し頻度を最大 5 回に制限できるようになります。 1秒あたりの回数。さて、この関数を実装しましょう。疑似コードは次のとおりです:

class UserLogin
{
    // …… 省略属性和部分方法
    
    public function login ($name, $pass)
    {
        // 限流
        $limit = new Limit();
        if ($limit->restrict()) {
            // ……
        }
        
        // 登录业务
    }
    
    public function reg ($name, $pass)
    {
        // 限流
        $limit = new Limit();
        if ($limit->restrict()) {
            // ……
        }
        
        // 注册业务
    }
}

上記のコードを見てみましょう。これにはいくつかの問題があります。まず、電流制限コードがビジネス コードに侵入しており、ビジネス コードと高度に結合しています。ビジネスコード。第二に、電流制限はビジネス規範とは何の関係もなく、単一責任の原則に違反します。

実装

次に、プロキシ モードを使用して上記のコードを書き換えます。書き換えられたコードは次のとおりです。上記の方法は、実装プログラミングではなくインターフェイスの設計思想に基づいていますが、元のクラスがインターフェイスを定義していない場合、またはこのクラスが弊社で開発および保守されていない場合、プロキシ モードを実装するにはどうすればよいでしょうか?

この外部クラスの拡張には、通常、継承メソッドを使用して実現します。

interface IUserLogin
{
    function login ();
    function register ();
}

class UserLogin implements IUserLogin
{
    // …… 省略属性和部分方法
    
    public function reg ($uname, $pass)
    {
        // 注册业务
    }
    
    public function login ($uname, $pass)
    {
        // 登录业务
    }
}

class UserLoginProxy implements IUserLogin
{
    private $limit = null;
    private $login = null;
    
    public function __construct(Limit $limit, Login $login)
    {
        $this->limit = $limit;
        $this->login = $login;
    }
    
    public function login($uname, $pass)
    {
        if ($this->limit->restrict()) {
            // ...
        }
        return $this->login->login($uname, $pass);
    }
    
    public function register($uname, $pass)
    {
        if ($this->limit->restrict()) {
            // ...
        }
        return $this->login->register($uname, $pass);
    }
}

上記のコードを見てください。何か問題はありますか?この同様のコード

class UserLogin
{
    public function reg ($uname, $pass)
    {
        // 注册业务
    }
    
    public function login ($uname, $pass)
    {
        // 登录业务
    }
}

class UserLoginProxy extends Login
{
    private $limit = null;
    
    public function __construct(Limit $limit, Login $login)
    {
        $this->limit = $limit;
        $this->login = $login;
    }
    
    public function login($uname, $pass)
    {
        if ($this->limit->restrict()) {
            // ...
        }
        return parent::login($uname, $pass);
    }
    
    public function reg($uname, $pass)
    {
        if ($this->limit->restrict()) {
            // ...
        }
        return parent::register($uname, $pass);
    }
}

が 2 回出現していることがわかります。ここでは、電流制限関数を 2 つのメソッドに追加するだけですが、UserLogin クラスに 10 個のメソッドがあり、各メソッドに電流制限関数を追加したい場合、このコードを 10 回コピーする必要があります。 10 個のクラスのすべてのメソッドに電流制限機能を追加する場合、各クラスに 10 個のメソッドがある場合、上記の電流制限コードを 100 回繰り返すことになります。

もちろん、電流制限コードを関数にカプセル化して上記の問題を解決できると言うでしょう?しかし、解決できない問題がまだあり、元のクラスのすべてのメソッドをプロキシ クラスで再実装する必要があります。上記の元のクラスに reg メソッドとlogin メソッドがあるのと同様に、プロキシ クラスにも reg メソッドとlogin メソッドがあります。

動的プロキシ上記の問題を解決するには、動的プロキシを使用します。動的プロキシを使用する場合は、PHP のリフレクション メカニズムを理解して使用する必要があります。

php には完全なリフレクション API があり、クラス、インターフェイス、関数、メソッド、拡張機能をリバース エンジニアリングする機能が追加されています。さらに、Reflection API は、関数、クラス、メソッドからドキュメント コメントを抽出するメソッドを提供します。 PHP リフレクションに関する知識については、ここでは詳しく説明しませんので、各自で調べてください。

リフレクションを使用するとパフォーマンスが大幅に消費されるため、通常の状況では使用しないでください。

リフレクションを使用して動的プロキシを実装する方法を示します。疑似コードは次のとおりです:

if ($this->limit->restrict()) {
    // ...
}

テスト コードは次のとおりです:

class UserLogin
{
    public function reg ($uname, $pass)
    {
        // 注册业务
        echo '注册业务' . PHP_EOL;
    }
    public function login ($uname, $pass)
    {
        // 登录业务
        echo '登录业务' . PHP_EOL;
    }
}
class LimitProxy
{
    // 用来保存多个实例对象
    private $target = [];
    public function __construct(Object $obj)
    {
        $this->target[] = $obj;
    }
    public function __call($name, $arguments)
    {
        foreach ($this->target as $obj) {
            $ref = new \ReflectionClass($obj);
            if ($method = $ref->getMethod($name)) {
                if ($method->isPublic() && !$method->isAbstract()) {
                    // 限流
                    echo "这里是限流业务处理" . PHP_EOL;
                    $result = $method->isStatic() ? $method->invoke(null, $obj, ...$arguments) : $method->invoke($obj, ...$arguments);
                    return $result;
                }
            }
        }
    }
}

# #アプリケーション シナリオ

アクセス制御 (保護エージェント)。たとえば、システムにはオーダー モジュールがあり、元々はこのモジュールにも権限制御がありましたが、指定した IP アドレスを持つクライアントのみがアクセスできるようにし、プロキシ モードを使用できるようにします。
  • リモート サービスのローカル実行 (リモート プロキシ) は、サービス オブジェクトがリモート サーバー上にある状況に適しています。
  • ビジネス コードで非機能要件 (電流制限、統計、ログなど) を開発します。
  • キャッシュ アプリケーション。たとえば、次のようになります。キャッシュ プロキシを追加します。キャッシュが存在する場合は、キャッシュ プロキシを呼び出してキャッシュ データを取得します。キャッシュが存在しない場合は、元のインターフェイスを呼び出します。

以上がPHP デザイン パターンのプロキシ パターンを 1 つの記事で理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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