web-dev-qa-db-ja.com

ビジネスロジックに拡張メソッドを使用する必要があるか

C#ではExtension methods

拡張メソッドを使用すると、新しい派生型を作成したり、再コンパイルしたり、元の型を変更したりすることなく、既存の型にメソッドを追加できます。

拡張メソッドは特別な種類の静的メソッドですが、拡張型のインスタンスメソッドであるかのように呼び出されます。

ただし、あまり設計されていない段階で、ビジネスロジックを含む具象クラスを置き換え、それらをExtension Methods

たとえば、このようなもの(非常に単純化した例)を置き換えることができるなど、利点は最初はすっきりしているように見えました。

var AddressUtils = new AddressUtils();
AddressUtils.CleanAddress(order);

var ValidationUtils = new ValidationUtils();
ValidationUtils.ValidateCustomer(Order);

Order.CleanAddress();
Order.ValidateCustomer();

つまり、多くのステートレスインスタンス化可能クラスを、コードを読みやすくするための短い静的メソッド(構文シュガー)に置き換えていました。これは本当に私と一緒に座ったことはありません。

これで、さまざまなメソッドを含む静的クラスの束ができました。大多数は、ジェネリックまたはインターフェイス駆動でもありません。つまり、使い捨てです。

これに加えて、静的クラスはテスト駆動開発には適さないという一般的な概念があります。

だから代替案は本当に

  • 具体的なユーティリティスタイルヘルパークラスに戻る
  • ロジックを何らかのDIサービスにカプセル化します
  • または、Model it selfにロジックを追加します。
  • または、それらを使用する必要のあるさまざまなサービスに再利用可能なロジックが散在しています。

最後から2番目のオプションに関しては、(ほとんどのモデルと同様に)順序は実際にはデータエンティティであり、ビジネスロジックをドメインモデルにプッシュするのは適切ではない(または実現可能ではない)ようです。

したがって、私は(いくつかのより良いパターンがない限り)ヘルパークラス、拡張メソッド、DIサービス、ある種のエンティティベースのロジック、または予測できないスパゲッティファクトリを残しています。

6
user140075

引用した

拡張メソッドを使用すると、新しい派生型を作成したり、再コンパイルしたり、元の型を変更したりすることなく、既存の型にメソッドを追加できます

そして、それはあなたがそれらをほとんど独占的に使用すべき時です-あなたがその方法で型を拡張することが強く意味がある場合がありますが、あなたはできません新しい派生型を作成したり、再コンパイルしたり、他の方法で元の型を変更したりせずに、これを行います。

これの典型的なシナリオは次のとおりです:タイプがシールされており、それが管理下にない-おそらくサードパーティのライブラリ-または、アセンブリに追加してはならない追加の依存関係を必要とするメソッドの追加を避けたいタイプが定義されています。

したがって、ここで最初に確認することは、これらの制約が適用されるかどうかであり、適用されない場合は、追加のメソッドを配置するための好ましい場所はクラス自体である必要があります。コードを変更できないが、クラスがシールされていない場合は、拡張メソッドの代わりにサブクラス化を使用することを検討できます。この状況では、保護されたメンバーへのアクセスが必要でない限り、サブクラス化よりも拡張メソッドを使用します。この状況でサブクラス化を使用しても、テスト容易性やコード編成のいずれにおいても、実際にはメリットはありません。

テスト容易性について:拡張メソッドは、他の静的メソッドまたは非静的メソッドに比べてユニットテストが簡単でも困難でもありません。テスト性またはTDDは、このようなメソッドに依存する他のコードを個別にテストする必要がある場合にのみ問題になります。したがって、拡張メソッド自体を「モックアウト」する必要がある状況に遭遇した場合は、テスト目的でモックに簡単に置き換えることができるユーティリティクラスにメソッドをリファクタリングするときがきました。

したがって、拡張メソッドの使用は問題ありません。

  • 拡張したいタイプの責任範囲に明確に適合する(!)メソッドを持っている

  • タイプ自体を簡単に変更することはできません

  • 継承を使用できない、または使用したくない

  • 関数に依存するコードで関数をモックする必要はありません。

拡張メソッドで開始できない理由は実際にはないことに注意してください。拡張機能の制限に遭遇した場合は、コードをリファクタリングしてください。したがって、これを考えすぎないでください。これは、コードがビジネスロジック、UIコード、またはインフラストラクチャコードであることとはあまり関係がないことに注意してください。プログラムが十分に大きい場合、これらの「レイヤー」はそれぞれ異なるサブレイヤーとコンポーネントで構成される可能性があり、「国境を越えたタイプの拡張が必要です。

4
Doc Brown

これに加えて、静的クラスはテスト駆動開発には適さないという一般的な概念があります。

これは、これらの静的メソッドが外部状態にアクセスまたは変更する場合にのみ当てはまります。もし

Order.CleanAddress();

Orderのみを変更し、静的サービスを介したアクセスルールなどを変更しない場合、テストに関する限り不適合ではありません。

したがって、変更を検討する唯一の理由がテスト目的であり、メソッドが適切に動作している場合は、コードをそのままにしておきます。

2
David Arno