11

CodeIgniterを使用して Web アプリケーションを設計しています(ただし、この質問は Web アプリケーションのMVCパターンに一般的に当てはまると思います)。

データベース エンティティのモデル クラスを設計する場合 (たとえば、BlogEntry説明用に)、基本的に 2 つの選択肢があります。

「古典的な OOP」アプローチは、クラスがエンティティを表現できるようにすることです。つまり、クラスの 1 つのインスタンスがBlogEntryになります。CodeIgniter では、これは次のようなコードになります。

class Blogentry extends CI_Model {
    function load($id) {
      // Access database
      $this->id = $dbresult.id;
      $this->title = $dbresult.title;
      $this->author = $dbresult.author;
    }
}

いくつかのブログ エントリにアクセスするには$this->load->model('blogentry');、 を呼び出し$this->blogentry->load($id)てから、モデル クラス インスタンスを操作します。

私がよく目にするもう 1 つのアプローチは、モデルが何らかのデータ構造でエンティティを返すようにすることです。コード内:

class Blogentry extends CI_Model {
  function get_entry($id) {
    // Access database, yielding $dbresult
    return $dbresult;
}

これで私は書くだろう

$this->load->model('blogentry');
$the_entry = $this->blogentry->get_entry($id);

コントローラーで を操作し$the_entryます。この 2 番目のケースでは、クラスはファクトリクラスまたはビルダークラスに似ています。

これらの 2 つのアプローチのいずれかが、MVC で M を実行する「正しい方法」と見なされますか? 2 番目のアプローチの方が頻繁に見られると思いますが、それほど多くの MVC-Webapps は見ていません。最初または2番目のアプローチがより適切である理由について何か考えはありますか?

4

3 に答える 3

13

何よりもまず、CodeIgniter はMVC フレームワークではありません。最も適したパラダイムは、おそらくMVPまたはORM-Template-Adapter のようなものです。それでは、その命名の誤りに基づいて私の答えを分解しましょう。

古典的/伝統的な MVC (フレームワークが MVC であると主張するものではありません) では、モデルはクラスや単一のファイルではなく、すべてのドメイン ビジネス ロジックを含むレイヤーであり、通常はDomain Objectsのようなものだけで構成されます。Data Mappers、および呼び出し側エンティティとドメイン ロジックの間のインターフェイスを処理するもので、そのようなコードをコントローラーから除外します (MVC など)。Teresko はそれらを "サービス"と名付けましたが、これは準公式の名前としては十分です。

したがって、従来の MVC では、モデル レイヤーへのリクエストは「サービス」を介して受信され、ドメイン オブジェクトおよびデータ マッパーとやり取りします。

明らかに、これらすべては、CodeIgniter やその他のフレームワークが「MVC」と呼ぶものとはほとんど関係がありません。この設計パターン (略して「CIMVC」と呼びます) では、Model は Controller によって呼び出されて操作されるクラスであり、データベースと直接対話します。モデル内のメンバー変数にデータを保存することは、あまり意味がありませんが、同様のことに興味がある場合は、CIMVC で記述された ORM プラグイン/ライブラリを確認してください。(ただし、ORM ソリューションは、従来の MVC に準拠するのに優れているわけではありません...)

一般的な方法として、私が見たほとんどの CI アプリケーションは、処理のために「生の」データベース データをコントローラーに返します。これにより、ドメイン ビジネス ロジックがモデル内に保持されます。CIMVC での私の個人的な好みは、モデル内のドメイン ビジネス ロジック以外のものを最小限に抑える/排除することです。

tl;dr - CodeIgniter の「伝統的/適切な」MVC は基本的に不可能なので、CI コードを強制的に伝統的な MVC パラダイムに準拠させようとするのはばかげています (そして、狂気に陥る可能性があります)。

編集:モデル層のビジネスロジックに関する以前の混乱を明確にするために、はい、モデル層にすべてのビジネスロジックが必要です。ただし、追加のデータ処理 (並べ替え、操作など) が行われると、DRY および SRP 違反の危険な領域に移動します。モデルを再利用できるようにしたいので、アプリケーションの他の部分で使用できなくなるほど多くの特殊なロジックを追加しないように注意してください。

于 2012-08-06T17:52:11.033 に答える
4

CI の経験はありませんが、Symfony、Zend、Propel、および Doctrine の経験は豊富であるため、これは MVC パラダイムに関連する一般的な回答です。

教義を使用しているときに、特定の構造内でオブジェクトデータを返すには、その構造を指定するメソッドを追加するのが最善であることがわかりました。たとえば、Doctrine_Record オブジェクトにはtoArray()、オブジェクトを配列に変換できるメソッドがあるため、オブジェクト アクセサーを使用するか、またはtoArray() を呼び出して、オブジェクトを配列として扱うことができます。

// Accessing object data through available methods
foreach ($object->categories() as $category) {
    var_dump((string) $category);
}

// Accessing object data as an array
$objectAsArray = $object->toArray(true);

foreach ($objectAsArray as $element) {
    var_dump($element['Category']);
}

結局のところ、データへのアクセス方法は好みに基づいており、ニーズに合わせてデータをどのように操作するかは完全にあなた次第です。また、場合によっては、オブジェクトのハイドレーションがパフォーマンス ヒットになる傾向があるため、配列形式のデータを処理する方が高速です。

どのような方法でデータにアクセスしても、ビジネス ロジックをモデル レイヤーに保持して、コードの繰り返しにならないようにすることをお勧めします (DRY: Don't Repeat Yourself)。

于 2012-08-06T20:19:07.670 に答える
3

最初に理解しなければならないことは、CodeIgniter は適切な MVC または MVC にインスパイアされた設計パターンからはかけ離れているということです。CodeIgniter が実装するパターンに正式名称はありませんが、Ruby on Rails と密接な関係があります。

最も深刻な問題は、モデル レイヤーの実装方法に起因します。ドキュメント全体を通して、アクティブ レコードパターンを使用することをお勧めします。これは、それ自体がいくつかの設計上の問題を引き起こします。

もう一つの大きな問題は、ビューの欠如です。ビューは、プレゼンテーション ロジックを含むインスタンスである必要があります。これには、モデル層から取得した情報の表現に使用するテンプレートの選択が含まれます。ビューはテンプレートではなく、テンプレートを使用する構造です。

CodeIgniter の上に適切なモデル レイヤーを作成する最善の方法は、無視することCI_Modelです。なぜなら、このクラスを拡張してもメリットがないからです。代わりに のようなものを作成しますServices。これらの構造は、モデル層との相互作用のためのインターフェイス (オブジェクト指向の意味ではない) として機能する可能性があります。各サービスは、複数のドメイン オブジェクトマッパーを処理できます。

基本的に、サービスはコントローラーからコマンド/メッセージを受け取り、モデル層の状態を変更し、モデル層から情報を抽出する方法を提供します。通常、抽出はビューインスタンスで行われますが、CodeIgniter ではそれができません。情報の抽出は、データをテンプレートに渡す「コントローラー」でも行われます。

コードは次のようになります。

class Library 
{

    protected $current_document = null;

    public function acquire_document( $id )
    {
        $document = load_class('Document', 'domain_object');
        $document->set_id( $id );

        $mapper = load_class('Document', 'persistence');
        $mapper->fetch( $document );

        $this->current_document = $document;
    }

    public function get_document_information()
    {
        $document = $this->current_document;        

        if ( $document === null )
        {
            return 'empty';
            // you either did not acquire the document
            // or document was not found
        }
        return $document->get_details();
    }
}

MVC デザイン パターンは、実際には、モデル レイヤーとプレゼンテーション レイヤー (主にコントローラーとビューから作成する必要がある) の 2 つのレイヤーの組み合わせです。

コントローラーは、ドメイン オブジェクト (モデル レイヤーの一部) を直接操作するべきではありません。これは、抽象化が漏れていることを意味するためです。

したがって、結論として、「モデル クラス」と呼ばれるものは、情報を返す必要があります。

于 2012-08-07T03:11:33.980 に答える