ホームページ  >  記事  >  PHPフレームワーク  >  Laravelインターフェース指向プログラミング(実践)

Laravelインターフェース指向プログラミング(実践)

Guanhui
Guanhui転載
2020-05-21 11:06:213467ブラウズ

Laravelインターフェース指向プログラミング(実践)

インターフェイス指向プログラミングは、固定クラスではなくインターフェイスに基づいてアプリケーションを構築するコーディングにおける設計哲学です。

プログラマーであれば、インターフェイス指向プログラミング、固定クラスの代わりに抽象クラスを使用するなどのステートメントを聞いたことがあるかもしれません。

これらはすべて同じことを言っています。具体的なクラスではなく抽象インターフェイスに依存するようにアプリケーション コードを作成してください。 #########なぜ?

これが、この文を最初に聞いたときの私の正確な反応です。なぜクラスではなくインターフェイスを使用するのでしょうか?インターフェースを作成したとしても、そのインターフェースを実装するクラスを作成する必要があります。これは時間の無駄ではありませんか? ######もちろん違います! !

この世界で唯一変わらないものは変化そのものです。つまり、変化は永遠です。

プログラミングに関する限り、これには例外はありません。ビジネス ニーズは時間の経過とともに変化するため、コードも変更する必要があります。

したがって、コードは柔軟性を維持する必要があります。

インターフェイス指向プログラミングでは、コードを疎結合にして柔軟にすることができます。 #########どうやってするの?

以下のコードを観察してください。

class Logger {
    public function log($content) 
    {
        //日志保存到文件中.
        echo "Log to file";
    }
}

これは、ファイルにログを記録する単純なクラスです。コントローラー内で呼び出すことができます。

class LogController extends Controller
{
    public function log()
    {
        $logger = new Logger;
        $logger->log('Log this');
    }
}

しかし、複数の場所 (データベース、ファイル、クラウドなど) にログを記録する必要がある場合はどうすればよいでしょうか。

次に、これらの変更に対応するために LogController クラスと Logger クラスを変更します。

class Logger {
    public function logToDb($content) 
    {
        //将日志记录到 db.
    }
    public function logToFile($content) 
    {
        //将日志保存到 file.
    }
    public function logToCloud($content) 
    {
        //将日志存储到 cloud.
    }
}
class LogController extends Controller
{
    public function log()
    {
        $logger = new Logger;
        $target = config('log.target');
        if ($target == 'db') {
            $logger->logToDb($content);
        } elseif ($target == 'file') {
            $logger->logToFile($content);
        } else {
            $logger->logToCloud($content);
        }
    }
}

これで、さまざまな目標を記録できるようになりました。しかし、他のターゲット (ログなど) を Redis サーバーに追加したい場合はどうすればよいでしょうか?最後に、Logger クラスと LogController クラスの両方を変更します。

ご覧のとおり、これはすぐに私たちの手に負えなくなり、コードが乱雑になってしまいます。 Logger クラスはすぐにまとまりました。これは悪夢です。


したがって、物事を分割する必要があります。 SOLID 原則に従って、責任を適切なクラスに移すことができます。

class DBLogger
{
    public function log()
    {
        //将日志记录到 db
    }
}
class FileLogger
{
    public function log()
    {
        //将日志保存到 file
    }
}
class CloudLogger
{
    public function log()
    {
        //将日志存储到 cloud
    }
}

そして、コントローラーは次のように変更されます:

class LogController extends Controller
{
    public function log()
    {
        $target = config('log.target');
        if ($target == 'db') {
            (new DBLogger)->log($content);
        } elseif ($target == 'file') {
            (new FileLogger)->log($content);
        } else {
            (new CloudLogger)->log($content);
        }
    }
}

これははるかに優れています。ここで、さらにログ ターゲットを追加したい場合は、新しいクラスを作成し、それをコントローラーの if-else に追加できます。

ただし、ロガーの選択はコントローラーが引き続き担当します。コントローラーの場合、さまざまなロガーについて知り、その中から選択する必要はありません。コンテンツをログに記録するには、 log() メソッドを備えたロガー クラスが必要です。

インターフェースの使用

この状況はインターフェースの使用に適しています。では、インターフェースとは何でしょうか?

インターフェイスは、オブジェクトが実行できる操作を記述したものです。

この例では、コントローラーには log() メソッドを備えたロガー クラスのみが必要です。したがって、インターフェースには log() メソッドが必要であることを記述する必要があります。

interface Logger
{
    public function log($content);
}
ご覧のとおり、これには関数の宣言のみが含まれており、その実装は含まれていないため、抽象と呼ばれます。

インターフェイスを実装する場合、インターフェイスを実装するクラスは、インターフェイスで定義された抽象メソッドの実装の詳細を提供する必要があります。

この例では、Logger インターフェイスを実装するクラスは、抽象メソッド log() の実装の詳細を提供する必要があります。

その後、このインターフェイスをコントローラーに挿入できます。

class LogController extends Controller
{
    public function log(Logger $logger)
    {
        $logger->log($content);
    }
}

これで、コントローラーは、渡されたロガーのタイプを気にしなくなります。知っておく必要があるのは、Logger インターフェイスを実装する必要があるということだけです。

したがって、このインターフェイスを実装するには Logger クラスを変更する必要があります。

class DBLogger implements Logger
{
    public function log()
    {
        //将日志记录到 db
    }
}
class FileLogger implements Logger
{
    public function log()
    {
        //将日志存储到 file
    }
}
class CloudLogger implements Logger
{
    public function log()
    {
        //将日志保存到 cloud
    }
}

これで、既存のコードに手を加えずにロガーを追加できるようになりました。必要なのは、Logger インターフェイスを実装する新しいクラスを作成することだけです。

class RedisLogger implements Logger
{
    public function log()
    {
        //将日志存储到 redis
    }
}

私たちのコードは柔軟で低結合になっているようです。以前のコードを変更せずに、いつでも実装方法を変更できます。

Dependency Injection

Laravel フレームワークを使用している場合、サービス コンテナを使用してインターフェイスの実装を自動的に登録できます。

Laravel ではすぐに使用できるメソッド インジェクションが提供されているため、インターフェイスと実装をバインドするだけで済みます。

まず、ロガー構成ファイルを作成する必要があります。これと同じように

<?php
return [
    &#39;default&#39; => env(&#39;LOG_TARGET&#39;, &#39;file&#39;),
    &#39;file&#39; => [
        &#39;class&#39; => App\Log\FileLogger::class,
    ],
    &#39;db&#39; => [
        &#39;class&#39; => App\Log\DBLogger::class,
    ],
    &#39;redis&#39; => [
        &#39;class&#39; => App\Log\RedisLogger::class,
    ]
];
次に、app/Providersパスの下のAppServiceProvider.phpファイルに次のコードを追加します

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        $default = config(&#39;log.default&#39;);
        $logger = config("log.{$default}.class");
        $this->app->bind(
            App\Contracts\Logger::class, // the logger interface
            $logger
        );
    }
}

これにより、logger.php構成からデフォルトのロガーが読み取られます。ファイルを作成し、Logger インターフェイスにバインドします。このようにして、Logger インターフェースを使用すると、コンテナーが解析してデフォルトの Logger インスタンスを返します。

デフォルトのロガーは env() アシスタントを使用して指定されるため、ローカル環境のファイルや運用環境の db など、異なる環境で異なるロガーを使用できます。

概要

インターフェイスを使用すると、結合度の低いコードを記述し、抽象化レイヤーを提供できます。これにより、いつでも実装を変更できます。したがって、アプリケーションの可変部分はできる限りインターフェイス指向の方法で実装するようにしてください。

推奨チュートリアル: 「

PHP チュートリアル

以上がLaravelインターフェース指向プログラミング(実践)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はlearnku.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。