web-dev-qa-db-ja.com

静的クラスを使用したサービス層の実装

「サービス」レイヤー(または、サービスのような機能と思われるもの)を静的クラスとして構造化しました。各クラスは、消費するレイヤーのニーズをサポートするための一連の操作をまとめて提供する補完的な関数のグループです。

public static class ElementService
{
    public static Element GetElementByAtomicNumber(int atomic_number)
    {
        ElementRepositorySQL elementRepositorySql = new ElementRepositorySQL();

        return elementRepositorySql.Read(atomic_number);
    }
}

たとえば、コントローラーは、直接処理するのではなく、サービスレイヤーを使用してリポジトリの読み取り/書き込みを行います。

public class ElementController
{
    public ElementModel Model {get; set;}

    public void LoadModel(int atomic_number)
    {
        Model = new ElementModel();

        Element e = ElementService.GetElementByAtomicNumber(atomic_number);

        Model.Name = e.Name.ToUpper();
        Model.Weight = Math.Round(e.AtomicWeight,4).ToString();
    }
}

グッドOOPの10のゴールデンルール 、ルール#5は次のように述べています。

  1. ヘルパー、ユーティリティ、Cの静的クラスを避ける

残念ながら、静的クラスはグローバルな状態として頻繁に機能し、回避すべき非決定論を作成します。しかし、それはさらに悪化します。静的クラスは、パラメーターとして明示的に渡されなくてもコードのあらゆる場所で使用できるため、APIドキュメントでは明らかにされない秘密の依存関係を作成します。

サービスの呼び出しが設計されたレイヤー内で厳密に行われる場合、これがどのように多くの問題になるかわかりませんか?私は持っていますコントローラのみがサービス層を呼び出す規約。その特定のサービスのセットはコントローラーをサポートします。

最後に、重要なことですが、静的クラスを使用するコードは分離してテストできないため、単体テストは悪夢になります。

パフォーマンス上の理由で厳密に必要な場合を除き、静的クラスの使用は避けてください。静的変数は、定数オブジェクト(setterなしの静的プロパティの方が適していますが)またはファクトリクラス内のオブジェクトへのプライベート参照を保持するために引き続き問題ありません。

これらのサービスが提供する機能の大部分は非常に単純なので、単体テストはやりすぎ(IDによるレコードの読み取り/書き込み)だと思います。

これらの状況を考慮しても、静的クラスの実装をリファクタリングする価値はありますか?これはまともなコードのチャンクなので、同等のRoIが必要です。

7
samis

これらのサービスが提供する機能の大部分は単純なので、単体テストはやりすぎ(IDによるレコードの読み取り/書き込み)だと思います。

確かに、それは問題ではありません。問題は、すぐ上のレイヤーをユニットテストするときに、サービスレイヤーで依存関係を分離するができるかどうかです。 ElementController。できない場合は、すべての単体テストを実行するためにデータベースが必要であり、失敗したテストの原因がコントローラーの欠陥なのか、それより下のレイヤーの欠陥なのかを見分けることができません。データベース自体の不正なデータを含むサービススタック。

6
John Wu

これらの「ゴールデンルール」とYAGNIやSOLIDのようなプリンシパルがある理由は、それらが/に対しての議論が複雑であるが、一般的なプリンシパルが経験の浅いプログラマーをトラブルから守ってくれることを要約するからです。

'静的を使用しない'の場合は、明らかにalwaysを使用するのが間違っています。しかし、なぜルールが存在するのか理解できない場合は、それに従うことをお勧めします。

私の見解では、このルールの主な理由はOOPによるものです。開発者はOOPコードを書き始め、呼び出したい一般的なメソッドを持つオブジェクトのインスタンスへの参照がないことを発見し、メソッドを静的にすることで問題を解決します。

これは当面の問題を解決しますが、OOPではありません。学生は「なぜOOPではないのか」と質問します。そして、「静力学があるから」という簡単な答えが与えられます。したがって、ルール。

ただし、特定のケースでは、サービス層を静的にすることの(他の中でも)実用的な欠点は、それをモックしてコントローラーを単体テストできないことです(ホスティングレイヤーで呼び出します)。

たとえば、個人的には、通常、静的ファイルから結果を返すモックサービスレイヤーを作成し、これをWeb API /コントローラーに挿入して、APIを使用するコンポーネントの統合テストで結果のサイトを使用します。

サービスレイヤーの静的な実際の実装なしではコントローラーをコンパイルできないため、これは静的サービスレイヤーでは不可能です。

4
Ewan

静的クラス/メソッドを含む、または使用するコードはOOPではありません。 OOPの利点はありません。OOPを使用するかどうかは、あなたの決定のみですが、その決定に取り組む前に、あなたが何であるかを理解する必要がありますOOPの意味をよく理解して失うこと。

あなたがすでに知っているなら、あなたが失うものとあなたが得るもの(より単純なコード、時間など)のバランスをとることによってあなたの決心をしてください。

あなたが知らないなら、ここでもっと読んでください:

1