ホームページ  >  記事  >  バックエンド開発  >  PHP デザインパターンの責任連鎖モデルを 1 つの記事で理解する

PHP デザインパターンの責任連鎖モデルを 1 つの記事で理解する

齐天大圣
齐天大圣オリジナル
2020-08-08 08:20:111962ブラウズ

責任連鎖モデルは動作設計モデルです。リクエストはプロセッサ チェーンに沿って送信されます。リクエストを受信した後、各プロセッサはリクエストを処理するか、チェーン上の次のプロセッサにリクエストを渡すことができます。チェーン上の各プロセッサには独自の処理責任があるため、責任チェーン モデルと呼ばれます。

シナリオ

現在システムがあり、そのシステムへのアクセスを制限したいとします。 1 つ目はログイン認証で、このシステムへのすべてのリクエストを取得するにはログインする必要があります。

しばらくして、上司はクローラー対策プログラムを追加する必要があると感じました。上司の最大の任務は、すぐに元の認証コードにクローラー対策機能を追加することです。現時点では、ログイン検証とクローラ対策検証はそれほど複雑ではありません。しかし、数日後、上司は電流制限の検証を追加する必要があると感じました...数日後、上司は…

検証に関連するコード ブロックが肥大化し、コードを読み取ったり保守したりすることが困難になりました。このとき、責任連鎖モデルを使って検証機能システムを書き直すと、次のようになります。

PHP デザインパターンの責任連鎖モデルを 1 つの記事で理解する

責任連鎖モデルにより、複数のプロセッサがリクエストを処理する機会があります。元のモジュールを複数のプロセッサに分割して処理すると、単一責任の原則に準拠し、コードの可読性が大幅に向上します。また、拡張も非常に簡単で、新たな検証機能が必要な場合には、開閉原理に準拠した新しいプロセッサを追加するだけで済みます。

責任連鎖パターン構造

責任連鎖パターン構造のコードを完成させましょう。各ハンドラーの機能は非常に単純で、リクエストを処理し、次のリクエスト ハンドラーを設定することです。以下はサンプル コードです:

abstract class AHandler
{
    protected $nextHandler = null;
    
    public function setNext (AHandler $handler)
    {
        $this->nextHandler = $handler;
    }
    
    abstract public function handler ();
}
class Handler1 extends AHandler
{
    public function handler()
    {
        $handled = false;
        
        // 处理请求
        echo 'Handler1接受到了请求' . PHP_EOL;
        
        if (!$handled && $this->nextHandler) {
            $this->nextHandler->handler();
        }
    }
}
class Handler2 extends AHandler
{
    public function handler()
    {
        $handled = false;
        
        // 处理请求
        echo 'Handler2接受到了请求' . PHP_EOL;
        
        if (!$handled && $this->nextHandler) {
            $this->nextHandler->handler();
        }
    }
}
class Handler3 extends AHandler
{
    public function handler()
    {
        $handled = false;
        
        // 处理请求
        echo 'Handler3接受到了请求' . PHP_EOL;
        
        if (!$handled && $this->nextHandler) {
            $this->nextHandler->handler();
        }
    }
}

使用コードの例は次のとおりです:

$handler1 = new Handler1();
$handler2 = new Handler2();
$handler3 = new Handler3();
$handler1->setNext($handler2);
$handler2->setNext($handler3);

$handler1->handler();

上記のコードは責任の連鎖の構造を完成させていますが、まだいくつかの問題があります。プログラマはビジネスまたは責任連鎖モデルを理解していません。明確すぎると、次のコードをハンドラー メソッドに追加するのを忘れる可能性があります。

if (!$handled && $this->nextHandler) {
    $this->nextHandler->handler();
}

その場合、責任連鎖は中断されます。さらに、10 個以上のプロセッサがある場合は、10 個の新しいプロセッサが作成され、setNext が 9 回実行されます。うっかり間違ったことを書いてしまったら、恥ずかしい思いをすることになります。

さて、上記のコードを変更してみましょう。変更後のコードは次のとおりです:

abstract class AHandler
{
    protected $nextHandler = null;
    
    public function setNext (AHandler $handler)
    {
        $this->nextHandler = $handler;
    }
    
    // 使用了模板方法模式,防止程序员忘记写下段代码
    public function handler ()
    {
        if (!$this->doHandler() && $this->nextHandler) {
            $this->nextHandler->handler();
        }
    }
    
    abstract public function doHandler ();
}

class Handler1 extends AHandler
{
    public function doHandler()
    {
        $handled = false;
        
        // 处理请求
        echo 'Handler1接受到了请求' . PHP_EOL;
        
        return $handled;
    }
}
class Handler2 extends AHandler
{
    public function doHandler()
    {
        $handled = false;
        
        // 处理请求
        echo 'Handler2接受到了请求' . PHP_EOL;
        
        return $handled;
    }
}

class Handler3 extends AHandler
{
    public function doHandler()
    {
        $handled = false;
        
        // 处理请求
        echo 'Handler3接受到了请求' . PHP_EOL;
        
        return $handled;
    }
}

class HandlerChain
{
    private $handlerChains = [];
    
    public function __construct(array $handlerChains)
    {
        $this->handlerChains = $handlerChains;
    }
    
    public function addHandler (AHandler $handler)
    {
        $this->handlerChains[] = $handler;
    }
    
    public function handler ()
    {
        $hdCnt = count($this->handlerChains);
        
        for ($i = 0; $i < $hdCnt; $i ++) {
            if (isset($this->handlerChains[$i]) 
                  && isset($this->handlerChains[$i+1])) {
                $this->handlerChains[$i]->setNext($this->handlerChains[$i+1]);
            }
        }
        
        $this->handlerChains[0]->handler();
    }
}

次に、コードを次のように使用します:

$handler1 = new Handler1();
$handler2 = new Handler2();
$handler3 = new Handler3();

$handerChian = new HandlerChain([$handler1, $handler2, $handler3]);
$handerChian->handler();

より簡単実装方法

実際には、責任連鎖パターンを実装するより簡単な方法があります。コードは次のとおりです。

abstract class AHandler
{
    abstract public function handler ();
}

class Handler1 extends AHandler
{
    public function handler()
    {
        $handled = false;
        // 处理请求
        echo &#39;Handler1接受到了请求&#39; . PHP_EOL;
        return $handled;
    }
}

// Handler2、Handler3代码省略


class HandlerChain
{
    private $handlerChains = [];
    
    public function __construct(array $handlerChains)
    {
        $this->handlerChains = $handlerChains;
    }
    
    public function addHandler (AHandler $handler)
    {
        $this->handlerChains[] = $handler;
    }
    
    public function handler ()
    {
        foreach ($this->handlerChains as $handler) {
            if ($handler->handler()) {
                break;
            }
        }
    }
}

概要

責任連鎖モデルを通じて、複数のプロセッサがリクエストを処理する機会があります。元のモジュールを複数のプロセッサに分割して処理すると、単一責任の原則に準拠し、コードの可読性が大幅に向上します。また、拡張も非常に簡単で、新しい機能が必要な場合には、新しいプロセッサを追加するだけです。

一般的な設計パターンの定義は、プロセッサがリクエストを処理できない場合、リクエストを次のプロセッサに渡すというものです。実際には、各プロセッサがリクエストを処理するというバリエーションもあります。

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

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