3

私は開発の選択肢として NTiers の大ファンです。もちろん、すべてのシナリオに適合するわけではありません。

私は現在、新しいプロジェクトに取り組んでおり、通常の作業方法を試して、それをクリーンアップできるかどうかを確認しようとしています。私はとても悪い子で、プレゼンテーション レイヤーにコードを入れすぎていました。

私の通常のビジネス層構造はこれです(基本的な見方):

  • 仕事
    • サービス
      • FooComponent
        • フーヘルパーズ
        • Fooワークフロー
      • BahComponent
        • バーヘルパーズ
        • Bahワークフロー
    • ユーティリティ
      • 一般
      • ExceptionHandlers
      • 輸入業者
      • 等...

上記により、それぞれのヘルパーを介して Foo オブジェクトと Bah オブジェクトを直接保存するための優れたアクセスが得られます。

XXXHelpers を使用すると、それぞれのオブジェクトを保存、編集、およびロードできますが、オブジェクトを子オブジェクトと共に保存するロジックはどこに配置すればよいでしょうか。

例えば:

以下のオブジェクトがあります(私が知っているオブジェクトはあまり良くありません)

  • 従業員
  • 従業員の詳細
  • 社員会員
  • 社員紹介

現在、私はこれらすべてをプレゼンテーション層で構築してからヘルパーに渡しますが、これは間違っていると思います。データは、ビジネス層のプレゼンテーションの上の単一のポイントに渡され、そこで整理されるべきだと思います。

しかし、このロジックをどこに配置し、セクターを何と呼ぶか​​について、私は少し途方に暮れています。それは、EmployeeManager またはこのようなものとしてユーティリティの下に移動しますか?

あなたならどうしますか?私はこれがすべて好みであることを知っています。

より詳細なレイアウト

ワークフローには、DataRepository への直接のすべての呼び出しが含まれています。次に例を示します。

public ObjectNameGetById(Guid id)
{
    return DataRepository.ObjectNameProvider.GetById(id);
}

次に、ヘルパー プロバイダーがワークフローにアクセスします。

public ObjectName GetById(Guid id)
{
    return loadWorkflow.GetById(id);
}

これは重複するコードを削減するためです。ワークフローで getBySomeProperty を 1 回呼び出してから、他の操作を実行してさまざまな方法でデータを返すことができるヘルパーで複数の呼び出しを行うことができるためです。悪い例は public GetByIdAsc と GetByIdDesc です。

DataRepository を使用してデータ モデルへの呼び出しを分離することで、モデルを別のインスタンスに交換することが可能になるということですが (そう考えていました)、ProviderHelper は分解されていないため、そのままでは交換できません。残念ながらEFにハードコードされています。アクセス テクノロジーを変更するつもりはありませんが、将来的には、代わりに実装したいと思うかもしれない、より優れたもの、またはすべてのクールな子供たちが現在使用しているものがあるかもしれません。

プロジェクト名.Core

projectName.Business
    - Interfaces
        - IDeleteWorkflows.cs
        - ILoadWorkflows.cs
        - ISaveWorkflows.cs
        - IServiceHelper.cs
        - IServiceViewHelper.cs
    - Services
        - ObjectNameComponent
            - Helpers
                - ObjectNameHelper.cs
            - Workflows
                - DeleteObjectNameWorkflow.cs
                - LoadObjectNameWorkflow.cs
                - SaveObjectNameWorkflow.cs
    - Utilities
        - Common
            - SettingsManager.cs
            - JavascriptManager.cs
            - XmlHelper.cs
            - others...

        - ExceptionHandlers
            - ExceptionManager.cs
            - ExceptionManagerFactory.cs
            - ExceptionNotifier.cs


projectName.Data
    - Bases
        - ObjectNameProviderBase.cs
    - Helpers
        - ProviderHelper.cs
    - Interfaces
        - IProviderBase.cs
    - DataRepository.cs

projectName.Data.Model
    - Database.edmx

projectName.Entities (Entities that represent the DB tables are created by EF in .Data.Model, this is for others that I may need that are not related to the database)
    - Helpers
        - EnumHelper.cs

プロジェクト名.プレゼンテーション

(アプリケーションの呼び出しが何であるかによって異なります)

projectName.web
projectName.mvc
projectName.admin

テスト プロジェクト

projectName.Business.Tests
projectName.Data.Test
4

2 に答える 2

3

興味深い質問に+1。

したがって、あなたが説明する問題はかなり一般的です-私は別のアプローチを取ります-最初に論理層を使用し、次にユーティリティとヘルパーの名前空間を使用して、完全に分解しようとします-その理由を説明します2番目。

しかし、最初に、ここで私が好むアプローチは非常に一般的なエンタープライズ アーキテクチャであり、簡単に強調しようとしますが、そこにはもっと深いものがあります。考え方を根本的に変える必要があります.NHibernateまたはEntityフレームワークを使用して、オブジェクトモデルを直接クエリし、ORMがデータベースとの間のマッピングや遅延読み込み関係などを処理できるようにします.これを行うと、実装できるようになります.ドメイン モデル内のすべてのビジネス ロジック。

最初に層 (またはソリューション内のプロジェクト)。

あなたのApplication.Domain

ドメイン モデル - 問題空間を表すオブジェクト。これらは、すべての主要なビジネス ロジックを備えた単純な古い CLR オブジェクトです。これは、サンプル オブジェクトが存在する場所であり、それらの関係はコレクションとして表されます。このレイヤーには永続性などを扱うものは何もありません。それは単なるオブジェクトです。

YourApplication.Data

リポジトリ クラス - これらは、ドメイン モデルの集約ルートの取得を扱うクラスです。

たとえば、サンプル クラスでは、Employee を確認せずに EmployeeDetails を確認することはほとんどありません (私が知っている前提ですが、要点は理解できます。請求書明細はより良い例です。通常、請求明細書には、請求書を個別にロードするのではなく)。そのため、集約ルートごとに1つのクラスを持つリポジトリクラスは、問題のORMを使用してデータベースから初期エンティティを取得し、クエリ戦略(ページングやソートなど)を実装し、集約ルートを消費者。リポジトリは、現在のアクティブなデータ コンテキスト (NHibernate の ISession) を消費します。このセッションの作成方法は、構築しているアプリの種類によって異なります。

YourApplication.ワークフロー

  • YourApplication.Services と呼ばれることもありますが、これは Web サービスと混同される可能性があります。
  • この層は、相互に関連する複雑なアトミック操作に関するものです。プレゼンテーション層で呼び出されるものがたくさんあるため結合が増えるのではなく、そのような操作をワークフローまたはサービスにラップできます。
  • 多くのアプリケーションでは、これがなくてもできる可能性があります。

他の層は、アーキテクチャと実装しているアプリケーションに依存します。

YourApplication.YourChosenPresentationTier

Web サービスを使用して層を分散している場合は、ドメインとコンシューマーの間で公開するデータのみを表す DTO コントラクトを作成します。ドメインからこれらのコントラクトにデータを出し入れする方法を知っているアセンブラーを定義します (ネットワーク上でドメイン オブジェクトを送信することはありません!)。

この状況で、クライアントも作成している場合、上で定義した操作とデータ コントラクトをプレゼンテーション層で使用します。各 DTO はビュー固有である必要があるため、DTO に直接バインドする可能性があります。

層を配布する必要がない場合は、分散アーキテクチャの最初のルールは配布しないことを思い出してください。ワークフロー/サービスとリポジトリを asp.net、mvc、wpf、winforms などから直接使用します。

それは、データ コンテキストが確立される場所を残すだけです。Web アプリケーションでは、通常、各リクエストは自己完結型であるため、リクエスト スコープのコンテキストが最適です。つまり、リクエストの開始時にコンテキストと接続が確立され、最後に破棄されます。選択した IoC/依存性注入フレームワークを取得して、要求ごとのコンポーネントを構成するのは簡単です。

デスクトップ アプリ、WPF、または winforms では、フォームごとにコンテキストがあります。これにより、モデルを更新するがデータベースには反映されない編集ダイアログのドメイン エンティティへの編集 (例: [キャンセル] が選択された) が、他のコンテキストに干渉したり、誤って永続化されたりすることがなくなります。

依存性注入

上記のすべては、最初にインターフェイスとして定義され、具体的な実装は IoC と依存性注入フレームワーク (私の好みはキャッスル ウィンザー) によって実現されます。これにより、個々の層を個別に分離、モック、および単体テストできます。また、大規模なアプリケーションでは、依存性注入は命の恩人です!

それらの名前空間

最後に、ヘルパー名前空間を失う理由は、上記のモデルではそれらを必要としないためですが、ユーティリティ名前空間と同様に、怠惰な開発者に、コードの一部が論理的にどこにあるかを考えない口実を与えるからです。MyApp.Helpers.* と MyApp.Utility.* は、コードがある場合、論理的に MyApp.Data.Repositories.Customers 内に属している可能性がある例外ハンドラーを言うことを意味します (おそらく、顧客参照は一意の例外ではありません)、遅延開発者は、特に考える必要なく、MyApp.Utility.CustomerRefNotUniqueException に配置するだけで済みます。

まとめる必要がある一般的なフレームワーク タイプのコードがある場合は、MyApp.Framework プロジェクトと関連する名前空間を追加します。新しいモデル バインダーを追加する場合は MyApp.Framework.Mvc に配置し、共通のログ機能の場合は MyApp.Framework.Logging に配置します。ほとんどの場合、ユーティリティまたはヘルパーの名前空間を導入する必要はありません。

要約

表面をなぞっただけですが、お役に立てば幸いです。これが私が今日ソフトウェアを開発している方法であり、意図的に簡潔にしようとしています。詳細について詳しく説明できる場合はお知らせください。この独断的な記事で最後に言いたいことは、上記はかなり大規模な開発のためのものだということです。メモ帳のバージョン 2 や企業の電話帳を書いている場合、上記はおそらく完全にやり過ぎです!!!

乾杯トニー

于 2010-08-25T22:24:42.900 に答える
0

このページには、アプリケーションのレイアウトに関する素敵な図と説明がありますが、記事のさらに下を見ると、アプリケーションは物理レイヤーに分割されていません (別のプロジェクト) - Entity Framework POCO リポジトリ

于 2010-08-31T12:15:36.807 に答える