4

バックグラウンド

これは長くて複雑な質問です。例として php/MySQL を使用しています (これは実際の例であるため) が、これは理論的には他の言語にも当てはまる可能性があります。我慢してください。

ORM のない MVC フレームワーク

独自のフレームワークを使用するアプリケーションを作成しています。さまざまな理由により、この質問に対する次の回答は受け入れられません。

  • フレームワークを使用しないのはなぜXですか?
  • XORMを使用しないのはなぜですか?

このアプリケーションは (私が作成した) 独自のクエリを実行します。

ビジネスの論理?

「ビジネス ロジック」は意味のない流行語のように思えますが、本質的には意味を持っています

クエリと、それらのクエリに基づいて結果セットを構築するロジック

また、MVC のモデルがすべてのビジネス ロジックを実行する必要があることも読みました。

User.php884行です

アプリがかなりうまく機能するようになったので、そのような嫌悪感を持たないようにリファクタリングしたいと思います。 User.php基本的にユーザーのモデルです(明らかに)。簡単に取り除ける責任がいくつかありますが、私が直面している大きなハードルは次のとおりです。

SOLID と MVC を調整するにはどうすればよいですか?

User.phpこれほど大きくなった理由は、そのファイルで User メンバーを必要とするクエリを実行したためです。ユーザーは大量の操作に使用されるため (単なる 以外にも多くのことを行う必要があります) 、 、 などCRUDを必要とするすべてのクエリは、このファイル内の関数によって実行されます。どうやらクエリはモデルにあるはずです(コントローラーではありません)が、これは何らかの方法で分割する必要があると思います。私は以下を達成する必要があります:useridusername

  • これらの必要なすべてのクエリを区分化された方法でカバーする API を作成する
  • 必要でない場合は DB 接続クラスへのアクセスを許可しない
  • Userビューにデータを追加します(User.php現在それを行っています-ビューオブジェクトはセッターによって注入されますが、これも悪いと思います)。

...だから私ができることはUserBranchManagerUserSiteManagerUserTagManager、 などの他のオブジェクトを作成することであり、それらのそれぞれに関連するクエリと、それらのクエリを実行するために注入された DB オブジェクトを含めることができますが、User::$userid実行する必要がある切望されたものをどのように取得しますかこれらのクエリ?それだけでなく、どうすれば合格できBranch::$branchidますか?それらのメンバーはプライベートであるべきではありませんか? それらにゲッターを追加しても、それは無意味になります。

また、オブジェクトがどれだけのことを行うべきかという線をどこに引くべきかもわかりません。多くの操作は似ていますが、それでも異なります。それぞれのクラスは非常にやり過ぎです。

可能な答え

助けが得られない場合、私が行う (または少なくとも実行しようとする) ことは、何らかの種類の依存性注入コンテナーを使用して、上記のオブジェクト (たとえばUserBranchManager) の依存関係を構築し、それらを関連するコントローラーに注入することです。これらにはDBandQueryオブジェクトがあります。Queryオブジェクトは、必要に応じてパラメーターをバインドするために低レベル モデル ( など) に渡すことができます。User高レベル モデルまたはそれらが呼び出されたものは、必要に応じてテンプレートにデータを追加するコントローラーに結果を返します。私が見たいくつかのハードルは、適切なコントラクトを作成することです (たとえば、UserControllerできればユーザー モデルの抽象化に依存する必要があります) が、特にビューに関しては、いくつかの詳細が必然的に必要になります。

私のとりとめのない質問に答えて、誰か知恵を提供できますか?

@teresko への返信

彼はここだけでなく、How should a model be structure in MVC?でも素晴らしい回答を提供してくれました。

コード

リクエストに応じて、ここにいくつかの非常に簡素化されたコードがあります (基本的に 1 つのリクエストにサービスを提供します)。いくつかの重要な注意事項:

  • 現在、コントローラーはクラスではなく、単なるファイルです
    • コントローラーは多くのルーティングも処理します
  • 「ビュー」オブジェクトはなく、テンプレートのみ
  • これはおそらく非常に悪いように見えます

これらも改善すべき点ですが、私は主にモデルについて心配しています(User特に制御不能になっているため):

#usr.php -- controller
$route = route();
$user = '';
$branch = '<TRUNK>';
if (count($route) > 0) {
   if (count($route) > 1) {
      list($user, $branch) = $route;
   }
   else {
      list($user) = $route;
   }
}

$dec = new Decorator('user');
$dec->css('user');

if (isset($_SESSION['user']) && $_SESSION['user']->is($user)) {
   $usr = $_SESSION['user'];
}
else {
   $usr = new User(new DB, $user);
}
$usr->setUpTemplate($dec, $branch);
return $dec->execute();

# User.php -- model
class User {
   private $userid;
   private $username;
   private $db;

   public function __construct(DB $db, $username = null) {
      $this->username = $username;
      $this->db = $DB;
   }

   public function is($user) {
      return strtolower($this->username) === strtolower($user);
   }

   public function setUpTemplate(Decorator $dec, $branch) {
      $dec->_title = "$this->username $branch";
      // This function runs a moderately complicated query
      // joining the branch name and this user id/name
      $dec->branch = $this->getBranchDisplay($branch);
   }
}

回答に関する質問

ここで答えてください:

  • あなたはキャッシング/認証/承認をやめることについて話します。これらは重要ですか?なぜ彼らはカバーされていないのですか?モデル/コントローラー/ルーターとどのように関係していますか?
  • Data Mapper例には、のようなメソッドを持つクラスがPersonあります..それらは何ですか? これらの計算には DB データが必要なようですが、どのように取得するのでしょうか? 葉っぱ。それは重要ではありませんか?getExemptionisFlaggedForAuditPerson Mapperselect
  • 「ドメインロジック」とは?

回答 5863870 (具体的にはコード例):

  • これらのファクトリ オブジェクトは抽象化すべきではありませんか (および による作成に依存しないでnewください)、またはこれらは特別なものですか?
  • API に必要な定義ファイルをどのように含めますか?
  • 依存関係をコンストラクターに注入するのが最善の方法について多くのことを読みました (必須の場合)。このようにファクトリを設定すると思いますが、オブジェクト/マッパー/サービス自体を設定しないのはなぜですか? 抽象化はどうですか?
  • コードの重複について心配していますか (たとえば_object_factory、クラス定義でメンバーを必要とするほとんどのモデル)。もしそうなら、どうすればこれを回避できますか?
  • を使用していますprotected。なんで?

特定のコード例を提供できる場合は、その方法で簡単に拾うことができるので、それが最適です。

あなたの答えが言っていることの理論を理解しており、それは大いに役に立ちました。私がまだ興味を持っている (完全には確信が持てない) のは、この API のオブジェクトの依存関係が最善の方法で処理されるようにすることです (最悪の場合はnewどこにでもあります)。

4

2 に答える 2

2

SOLID を混同しないでください (SOLID の詳細については、次のブログで説明しています: http://crazycoders.net/2012/03/confoo-2012-make-your-project-solid/

SOLID は、構築しようとしているアプリケーションを取り巻くフレームワークを検討する場合に最適です。データ自体の管理は別のことです。SOLID の S の単一の責任を、ユーザー、グループ、権限などの他のビジネス モデルに依存するビジネス モデルに実際に適用することはできません。

したがって、アプリケーションをビルドするときは、SOLID の一部を手放す必要があります。SOLID が優れているのは、アプリケーションの背後にあるフレームワークが強力であることを確認することです。

たとえば、独自のフレームワークとビジネス モデルを構築する場合、おそらく DATABASEACCESS 用に別の基本クラス MODEL を作成します。ただし、MODEL はデータを取得する方法を認識してはならず、データを取得する必要があることだけを知っておいてください。

例えば:

Good: 
    - MyApp_Models_User extends MyApp_Framework_Model
    - MyApp_Models_Group extends MyApp_Framework_Model
    - MyApp_Models_Permission extends MyApp_Framework_Model
    - MyApp_Framework_Model
    - MyApp_Framework_Provider
    - MyApp_Framework_MysqliProvider extends MyApp_Framework_Provider

      In this good part, you create a model like this:
      $user = new MyApp_Models_User(new MyApp_Framework_MysqliProvider(...));
      $user->load(1234);

このようにして、単一の責任での失敗を防ぎます。プロバイダーは、存在する多くのプロバイダーの1つからデータをロードするために使用され、モデルは抽出したデータを表します。データ、それがプロバイダーの仕事です...

Bad way:
    - MyApp_Model_User
    - MyApp_Model_Group
    - MyApp_Model_Permission

      define('MyDB',   'localhost');
      define('MyUser', 'user');
      define('MyPass', 'pass');
      $user = new MyApp_Models_User(1234);

この悪い方法を使用すると、まず単一の責任を壊します。モデルは何かを表し、データの入力/出力も管理します。また、モデルがデータベースに接続するための定数を定義する必要があることを示すことで依存関係を作成し、データベース メソッドを完全に抽象化します。それらを変更する必要があり、37 個のモデルがある場合は、やるべきことがたくさんあります。 ...

さて、悪い方法で作業したい場合はできます...私はまだそれを行っています、私はそれを認識していますが、時には、くだらない構造を持っていてリファクタリングしたい場合は、原則に反して作業することができ、またそうする必要があります正しくゆっくりとリファクタリングしてから、もう少しリファクタリングすると、SOLID と MVC の外観になります。

SOLID がすべてに当てはまるわけではないことを覚えておいてください。これは単なるガイドラインですが、非常に優れたガイドラインです。

于 2012-07-19T13:39:47.387 に答える