私はいくつかの研究開発作業を行っているので、デザインパターンを模索しています。私は最近、仕様パターンを読んでいて、この素晴らしい記事を参照されました。
私はコードの単純さと清潔さに興味をそそられましたが、他の手法を使用して同じ清潔さを実装することといくつかの比較を描き始めました。
サービス層の次のインターフェイスコントラクトを検討してください。
public interface IFooDataService
{
ICollection<Foo> GetFoosBySpecification(Specification<Foo> specification);
ICollection<Foo> GetFooByPredicate(Func<Foo,bool> predicate);
ICollection<Foo> GetFooBySearchArgs(FooSearchArgs searchArgs);
}
だから、いくつかの最初のポイント:
- 3つすべてがFooオブジェクトのコレクションを返します
- 3つすべてが1つの引数を取る
- 仕様方法は、特定の要件へのアクセスを制限します
- 述語法には基本的に制限はありません
- Search argsメソッドは、特定の要件へのアクセスを制限します
さて、実装に移りましょう。
public ICollection<Foo> GetFoosBySpecification(Specification<Foo> specification)
{
return fooDataRepository
.Find()
.Where(f => specification.IsSatisfiedBy(f))
.ToList();
}
public ICollection<Foo> GetFooByPredicate(Func<Foo, bool> predicate)
{
return fooDataRepository
.Find()
.Where(predicate)
.ToList();
}
public ICollection<Foo> GetFooBySearchArgs(FooSearchArgs searchArgs)
{
return fooDataRepository
.Find()
.WhereMeetsSearchCriteria(searchArgs)
.ToList();
}
実装のポイント:
- 3つすべての実装は非常に簡単です(1行の連鎖コード)
- フィルタリングされた仕様と検索引数は外部に実装されています。
- Search argsメソッドは、単にIEnumerable拡張メソッドを使用してargsを検査します
そうは言っても、上記の3つのテクニックのいずれかをどのような条件下で使用しますか?
仕様パターンについての私の考え:
- ビジネス/ドメイン要件を再利用可能なコンポーネントに分離するという点で優れています
- 非常に読みやすく、コードが英語を話せるようにします
- かなりの量のコードが含まれています(インターフェース、抽象クラス)。これを使用する場合は、抽象化を共通のアセンブリに配置します(したがって、ソリューションに静的ファイルがたくさんありません)。
- サービス層ではなく、仕様を変更するだけで要件を簡単に変更できます。
- ドメインロジックの最高のテスト容易性(仕様)
拡張メソッド(パイプとフィルター)に関する私の考え:
- 論理的には「重量があります」が、それでも同じ単純さをもたらします。
- クエリロジックをサービスレイヤーから静的メソッドに分離する
- それでも、ある種の「反映」が必要です(提供された検索引数を検査し、クエリを構築します)
- 特定のビジネス要件(特定のシナリオで便利)を考慮せずに、最初にアーキテクチャ(リポジトリ、サービスレイヤー)をコーディングできます
述語メソッドに関する私の考え:
- クエリをきめ細かく制御する必要がある場合に使用できます。
- 仕様がそれをやり過ぎているかもしれない小さなプロジェクトに適しています
私の最後の考えの論理は、ビジネス要件が事前にわかっているが、時間の経過とともに変化する可能性がある複雑なビジネスアプリケーションで作業している場合は、仕様パターンを使用するというものです。
しかし、「スタートアップ」であるアプリケーションの場合、つまり要件は時間の経過とともに進化し、複雑な検証なしでデータを取得する方法が多数ある場合は、パイプとフィルターのメソッドを使用します。
あなたの考えは何ですか?上記の方法のいずれかで問題が発生したことがありますか?何かお勧めはありますか?
新しいプロジェクトを開始しようとしているので、これらのタイプの考慮事項は重要です。
助けてくれてありがとう。
仕様パターンを明確にするための編集
これが仕様パターンの同じ使用法です。
Specification<Foo> someSpec; // Specification is an abstract class, implementing ISpecification<TEntity> members (And, Or, Not, IsSatisfiedBy).
someSpec = new AllFoosMustHaveABarSpecification(); // Simple class which inherits from Specification<Foo> class, overriding abstract method "IsSatisfiedBy" - which provides the actual business logic.
ICollection<Foo> foos = fooDataService.GetFoosBySpecification(someSpec);