Laravelプログラムアーキテクチャ設計構想:動作クラスの使用


アプリケーションのアーキテクチャについて話すと、「このコードはどこに置けばいいのか」という古典的な質問がよく聞かれます.Laravelはかなり柔軟なフレームワークなので、この質問に答えるのはそんなに簡単ではありません.私のビジネスロジックをModel層に書くべきですか、それともController層に書くべきですか.それとも他の場所ですか.
アプリケーションにアクセスポイントが1つしかない場合は、ビジネスロジックをControllerレイヤに書くことができます.しかし、現在より一般的な状況は、同じ機能モジュールを呼び出すアクセスポイントが多いことです.
たとえば、多くのアプリケーションには、コントローラを呼び出して登録に成功したビューまたは失敗したビューを返すユーザー登録機能があります.このアプリケーションにモバイル端末がある場合、返されるデータフォーマットがJSONであるため、モバイル端末ユーザに登録されたAPIを提供する可能性が高い.また、Laravelのartisanコマンドを使用して、特にプロジェクトの前期の開発段階でユーザーを作成することもよくあります.
上記の2つのコードは問題ないように見えるかもしれませんが、ビジネスロジックが増加するにつれて、コードが冗長になります.たとえば、新しいユーザーの登録が完了したら、ユーザーにメール通知を送信する機能を追加する必要がある場合は、上記の2つのコントローラにメールを送信するコードを追加する必要があります.しかし、コードの簡潔さと優雅さを維持するには、これらのビジネスロジックを他の場所に書くことができます.
「ビジネスロジックコードをどこに書くか」という質問には、どのフォーラムに行っても「サービス層を使用してcontroller層でこのサービスクラスを呼び出す」という一般的な答えが得られます.はい、そうです.問題はサービスクラスをどのように設計すればいいかです.UserServiceクラスを作成して、ユーザーユーザーに関連するすべてのビジネスロジックを実現し、このクラスを必要なControllerレイヤに注入しますか?それとも他の案がありますか?
神の穴を避ける
まず、すべてのコードを含む特定のモデルに単一のクラスを作成してみましょう.例:
完璧に見えます:私たちは任意のコントローラでcreate/delete方法を説明したり、使用したりして、私たちが望んでいる結果を得ることができます.しかし、このような実現にはどんな問題があるのだろうか.それは,我々が問題を解決する過程で通常単一のモデルをあまり使用しないことである.
例えば、あるユーザーにアカウントを作成したとき、同時にユーザーにblogを作成します.現在の方法でこのプロセスを実装する場合は、BlogServiceクラスを作成し、UserServiceクラスに依存を注入する必要があります.
アプリケーションのビジネスが増加するにつれて、数十~100個のサービスクラスがあり、そのうちのいくつかのサービスクラスは5~6個の他のサービスクラスに依存する必要があります.最終的な結果は、コードの冗長性と混乱の局面が現れ、この局面は私たちがすべての代価を惜しまずに避けたいと思っています.
単一アクションクラスの紹介
では、単一のサービスクラスにいくつかの方法を加えなければ、私たちはそれをいくつかのクラスに分けることにしましたか?以下は私が最近すべてのプロジェクトで採用した方法で、結果はとても良くて、皆さんにお勧めします.
まず、あまりにも漠然としたサービス用語を捨てて、私たちの新しいアクションクラスを理解し、それらが何であるか、何ができるかを定義しましょう.
  • 動作クラスには、CreateOrder、ConfirmCheckout、DeleteProduct、AddProductToCartなど、その機能を説明できる名前があるはずです.
  • APIとして1つの共通の方法しかないはずです.理想的には、handle()やexecute()のような同じメソッド名であるべきです.私たちの動作クラスに何らかのアダプタモードを実現する必要がある場合は、これは非常に便利です.
  • リクエストと応答が不明である必要があります.リクエストは処理されず、応答も送信されません.このような職責はコントローラが担うべきだ.
  • 他の動作クラスに依存することができる.
  • 実行を停止したり、所望の値を返したりすることがある場合は、Exceptionを放出することによって関連するビジネスロジックを強制的に実行し、呼び出し元(またはLaravelのExceptionHandler)に異常の表示/応答方法の責任を負わせる必要があります.

  • CreateUserアクションクラスの作成
    次に、前の例を見て、CreateUserという名前の単一アクションクラスで再構築します.
    メールアドレスが占有されている場合、この方法がなぜ異常を投げたのか知りたいかもしれません.これは検証を要求して保証したのではないでしょうか.もちろんいいです.しかし、アクションクラス内でビジネスロジックを実行したほうがいいのではないでしょうか.これにより、ロジックの理解とデバッグが容易になります.
    次のように、動作クラスを使用したコントローラコードを見てみましょう.
    現在、私たちがどんな修正をしても、ユーザー登録プロセスはAPIとWebバージョンで処理され、優雅で清潔です.
    アクションクラスのネスト
    もし、アクションクラスが1000人のユーザーをアプリケーションにインポートする必要がある場合.アクションクラスを作成し、上記のCreateUserクラスを引き続き使用できます.
    とてもきれいですね.Collection::map()メソッドに埋め込むことでCreateUserコードを再利用し、すべての新しいユーザーのセットを返すことができます.メールが占有されている場合は、Null Objectに戻るか、ログファイルに記録することができます.あなたはすでに考えているはずです.
    動作類の装飾
    次に、新しく登録したユーザーをログに記録したいとします.コードを動作クラスの内部に書くことも、装飾者モードを使うこともできます.
    次に、LaravelのIoCコンテナを使用して、LogCreateUserクラスをCreateUserクラスにバインドできます.後者のインスタンスが必要になるたびに、前者が注入されます.
    AppServiceProvider.php
    これにより、構成変数または環境変数を使用してログ記録機能のアクティブ化または非アクティブ化を制御することが容易になります.
    AppServiceProvider.php
    まとめ
    この方法を使うには多くのクラスが必要になるようです.もちろん、ユーザー登録は、コードの簡潔さを保証するための簡単な例にすぎません.プロジェクトの複雑さが増加し始めると、コードの所在と定義を明確に知っているため、アクションクラスの本当の価値はますます明らかになります.
    単一アクションクラスを使用するメリット:
  • コンパクトで単一の論理ドメインは、コードの重複を防止し、コードの再利用性を向上させ、安定を保つことができる.
  • は、様々なシーンについて独立したテストを容易に行う.
  • の意味のあるネーミングは、大規模なプロジェクトで読みやすいです.
  • は装飾しやすい.
  • プロジェクト全体の一貫性:コードがControllers、Modelsなどに分布することを防止する.

  • もちろん、この方法は私がここ数年Laravelを使ったいくつかの経験と私のいくつかのプロジェクトでの実践に基づいています.これは私にとって本当に役に立ち、今では中小規模のプロジェクトでも使用されています.
    もしあなたが違う方法があれば、私はとても楽しみに読んでいます.
    もっと近代的なPHP知識、Laravel/PHP知識コミュニティに行ってください