1

次のシナリオで私を修正してください。(質問は最後にあります)

(整理されていない同様の質問をしましたが、投票で終了しました。そのため、ここで質問を正確な回答で回答できる範囲にまとめました。)

nhibernate を ORM として使用して、複数のレイヤーを持つ Web アプリケーションを開発しています。私のレイヤー構造は次のとおりです

  1. モデル層
  2. リポジトリ層
  3. サービス層
  4. UIレイヤー

上記のレイヤーでは、クラスとインターフェイスは次のように配置されます。

ProductController.cs (UI レイヤー)

public class ProductController : Controller
{
    ProductServices _ProductServices;
    NHibernate.ISession _Session;

    public ProductController()
    {
        _Session = SessionManager.GetCurrentSession();

        _ProductServices = new ProductServices(
            new ProductRepository(), _Session);
    }
    // Cont..
 }

ProductServices.cs (サービス層)

public class ProductServices : IProductServices
{
    protected IProductRepository _ProductRepository;
    protected NHibernate.ISession _Session;

    public ProductServices(IProductRepository productRepository,
        NHibernate.ISession session)
    {
        _ProductRepository = productRepository;
        _Session = session;
        _ProductRepository.SetSession(_Session);
    }

    // cont...
}

ProductRepository.cs (リポジトリ レイヤー)

public class ProductRepository : IProductRepository
{
    NHibernate.ISession _Session;

    public void SetSession(NHibernate.ISession session)
    {
        _Session = session;
    }

    public IEnumerable<Product> FindAll()
    {
        return _Session.CreateCriteria<Product>().List<Product>();
    }

    //cont..
}

UI レイヤーから、セッションごとのリクエストとしてセッションを作成し、クラス コンストラクターを使用してサービス レイヤーに挿入します。次に、メソッドを使用してリポジトリのセッションを設定します。

_Session をコンストラクターとしてリポジトリに直接渡すと、サービス層の下でそれを制御できなくなるのではないかと心配しています。また、 Web サービス層を使用するための将来の拡張計画もあります。

**同じコードを繰り返しているため、すべてのメソッド_Sessionにコードを書かずに、すでに設定されているProductRepositoryクラスの各メソッドで確認する方法はありますか。if(_Session==null)

** 上記のパターンが間違っている場合は、この目標を達成する正しい方法を教えてください。

4

2 に答える 2

5

あなたがしていることは私を少し驚かせました。でコンストラクター注入パターンを適用しますProductService。これは間違いなく進むべき道です。一方、依存関係を に注入しているわけではありませんProductControllerが、そのクラスは静的クラス (これは Service Locator のアンチパターンです) を介してそれらの依存関係の 1 つを要求しており、ProductServicesクラス自体を作成しています。ProductServicesこれにより、このクラスのテストが難しくなり、アプリケーションの柔軟性と保守性が低下します。これは、クラスが複数の場所で使用されている場合、クラスの使用を簡単に変更、装飾、または傍受できないためです。

また、 の依存関係にコンストラクター注入を (正しく) 使用していProductServicesますが、 にもコンストラクター注入パターンを適用するのではなく、それらの依存関係を製品リポジトリに渡してProductResopistoryいます。

この目標を達成するための正しい方法を教えてください。

正しい方法は、コンストラクター注入パターンをあらゆる場所に適用することです。これを行うと、コードは次のようになります。

public class ProductController : Controller
{
    private ProductServices _ProductServices;

    public ProductController(ProductServices services)
    {
        _ProductServices = services;
    }
    // Cont..
 }

public class ProductServices : IProductServices
{
    private IProductRepository _ProductRepository;

    public ProductServices(
        IProductRepository productRepository)
    {
        _ProductRepository = productRepository;
    }
    // cont...
}

public class ProductRepository : IProductRepository
{
    private ISession _Session;

    public ProductRepository (ISession session)
    {
        _Session = session;
    }

    public IEnumerable<Product> FindAll()
    {
        return _Session
            .CreateCriteria<Product>().List<Product>();
    }
    //cont..
}

各クラスが自身で使用する依存関係のみを取り込む方法を確認してください。したがって、ProductControllerProductServicesに依存しません(私は のみが必要ISessionであると仮定しました)。クラスの観点から見ると、すべてがはるかに単純になっていることがわかりますか?ProductRepoistoryISession

ここで実際に問題を解決しましたか? すべてのクラスを依存関係グラフに接続するという問題を移動したようです。はい、問題を解決しました。そして、これは良いことです。これで、各クラスを個別にテストできるようになり、追跡が容易になり、アプリケーション全体がより保守しやすくなりました。

ただし、アプリケーションのどこかに をProductController作成する必要があります。これは次のようになります。

new ProductController(
    new ProductServices(
        new ProductRepository(
            SessionManager.GetCurrentSession())));

通常の構成では、ASP.NET MVC はコントローラー クラスを作成しますが、そのためには既定のコンストラクターが必要です。コンストラクター インジェクションを使用してコントローラーを結び付けたい場合 (必ず実行する必要があります)、これを機能させるには「特別な」操作を行う必要があります。

ASP.NET MVC では、既定ControllerFactoryのクラスをオーバーライドできます。これにより、コントローラー インスタンスの作成方法を決定できます。ただし、アプリケーションが成長し始めると、手動で依存関係グラフを作成していると、すぐに非常に扱いにくくなります (最後の例が示すように)。この場合、依存性注入フレームワークを使用する方がはるかに優れています。それらのほとんどには、ASP.NET MVC との統合を可能にし、MVC コントローラーでのコンストラクター インジェクションの使用を自動的に許可する機能/パッケージが含まれています。

まだ終わってないか?ええと... 私たちは今までですか?あなたのデザインには、私の脳内でフラグを立てたものが 1 つあります。システムには という名前のクラスが含まれていProductServicesます。大雑把な推測ですが、その名前Servicesは、製品に関連するすべてのビジネス オペレーションをそのクラス内にラップしたように見えます。システムのサイズ、チームの人数、必要な変更の量によっては、これが問題になる可能性があります。たとえば、システムの保守性を維持するために、横断的な関心事 (ロギング、検証、プロファイリング、トランザクション管理、フォールト トレランスの改善など) を効果的に適用するにはどうすればよいでしょうか?

したがって、すべての操作を 1 つのProductServicesクラスにラップする代わりに、各ビジネス トランザクション / ユース ケースに独自のクラスを与え、それらすべてのクラスに同じ (汎用) インターフェースを適用してみてください。この説明は少し曖昧かもしれませんが、小規模および大規模システムの保守性を向上させる優れた方法です。詳細については、こちらをご覧ください。

于 2013-01-07T10:24:43.800 に答える
0

Autofac などの依存性注入コンテナーを使用して、セッションをインスタンス化し、その有効期間を管理できます。セッションをインスタンス化する責任は Autofac に任せ、依存関係を必要とするすべてのクラスに ISession インターフェイスを挿入するだけです。この投稿をご覧ください: Autofac を使用した NHibernate ISession の管理

MVC3 を使用した Autofac の構成については、次の wiki ページも役立ちます: http://code.google.com/p/autofac/wiki/MvcIntegration3

于 2013-01-07T08:16:56.050 に答える