バックグラウンド
これは長くて複雑な質問です。例として php/MySQL を使用しています (これは実際の例であるため) が、これは理論的には他の言語にも当てはまる可能性があります。我慢してください。
ORM のない MVC フレームワーク
独自のフレームワークを使用するアプリケーションを作成しています。さまざまな理由により、この質問に対する次の回答は受け入れられません。
- フレームワークを使用しないのはなぜ
X
ですか? X
ORMを使用しないのはなぜですか?
このアプリケーションは (私が作成した) 独自のクエリを実行します。
ビジネスの論理?
「ビジネス ロジック」は意味のない流行語のように思えますが、本質的には意味を持っています
クエリと、それらのクエリに基づいて結果セットを構築するロジック
また、MVC のモデルがすべてのビジネス ロジックを実行する必要があることも読みました。
User.php
884行です
アプリがかなりうまく機能するようになったので、そのような嫌悪感を持たないようにリファクタリングしたいと思います。 User.php
基本的にユーザーのモデルです(明らかに)。簡単に取り除ける責任がいくつかありますが、私が直面している大きなハードルは次のとおりです。
SOLID と MVC を調整するにはどうすればよいですか?
User.php
これほど大きくなった理由は、そのファイルで User メンバーを必要とするクエリを実行したためです。ユーザーは大量の操作に使用されるため (単なる 以外にも多くのことを行う必要があります) 、 、 などCRUD
を必要とするすべてのクエリは、このファイル内の関数によって実行されます。どうやらクエリはモデルにあるはずです(コントローラーではありません)が、これは何らかの方法で分割する必要があると思います。私は以下を達成する必要があります:userid
username
- これらの必要なすべてのクエリを区分化された方法でカバーする API を作成する
- 必要でない場合は DB 接続クラスへのアクセスを許可しない
User
ビューにデータを追加します(User.php
現在それを行っています-ビューオブジェクトはセッターによって注入されますが、これも悪いと思います)。
...だから私ができることはUserBranchManager
、UserSiteManager
、UserTagManager
、 などの他のオブジェクトを作成することであり、それらのそれぞれに関連するクエリと、それらのクエリを実行するために注入された DB オブジェクトを含めることができますが、User::$userid
実行する必要がある切望されたものをどのように取得しますかこれらのクエリ?それだけでなく、どうすれば合格できBranch::$branchid
ますか?それらのメンバーはプライベートであるべきではありませんか? それらにゲッターを追加しても、それは無意味になります。
また、オブジェクトがどれだけのことを行うべきかという線をどこに引くべきかもわかりません。多くの操作は似ていますが、それでも異なります。それぞれのクラスは非常にやり過ぎです。
可能な答え
助けが得られない場合、私が行う (または少なくとも実行しようとする) ことは、何らかの種類の依存性注入コンテナーを使用して、上記のオブジェクト (たとえばUserBranchManager
) の依存関係を構築し、それらを関連するコントローラーに注入することです。これらにはDB
andQuery
オブジェクトがあります。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 データが必要なようですが、どのように取得するのでしょうか? 葉っぱ。それは重要ではありませんか?getExemption
isFlaggedForAudit
Person Mapper
select
- 「ドメインロジック」とは?
回答 5863870 (具体的にはコード例):
- これらのファクトリ オブジェクトは抽象化すべきではありませんか (および による作成に依存しないで
new
ください)、またはこれらは特別なものですか? - API に必要な定義ファイルをどのように含めますか?
- 依存関係をコンストラクターに注入するのが最善の方法について多くのことを読みました (必須の場合)。このようにファクトリを設定すると思いますが、オブジェクト/マッパー/サービス自体を設定しないのはなぜですか? 抽象化はどうですか?
- コードの重複について心配していますか (たとえば
_object_factory
、クラス定義でメンバーを必要とするほとんどのモデル)。もしそうなら、どうすればこれを回避できますか? - を使用しています
protected
。なんで?
特定のコード例を提供できる場合は、その方法で簡単に拾うことができるので、それが最適です。
あなたの答えが言っていることの理論を理解しており、それは大いに役に立ちました。私がまだ興味を持っている (完全には確信が持てない) のは、この API のオブジェクトの依存関係が最善の方法で処理されるようにすることです (最悪の場合はnew
どこにでもあります)。