一般的なタスクを実行し、アプリケーション全体から呼び出されるメソッドに静的クラスを使用する必要がありますか?


8

私は最後の数時間を費やして、staticクラスの使用について読み、それらを使用する必要があるかどうかを理解しようとしましたが、それでも何らかの結論には至っていません。議論はどちらにでも行くことができるようです。私のアプリケーションでは、「ヘルパークラス」と呼ばれるものを作成しました。これには、非常に一般的なタスクを実行し、アプリケーション全体(ASP.Net MVCWebアプリを使用C#)から呼び出されるメソッドが含まれています。簡単な質問は、それらが本当に静的かどうかです。 ?

これが私のヘルパーの例です。

public static class ActiveDirectoryHelper
{
    public static PrincipalContext GetPrincipalContext(string ouName)
    {
        var fullOUName = string.Concat("OU=", ouName,",DC=");

        return new PrincipalContext(ContextType.Domain, "", fullOUName, ConfigurationManager.AppSettings["ServiceAccountUser"], ConfigurationManager.AppSettings["ServiceAccountPassword"]);
    }

    public static PrincipalSearcher GetAllUsersInOU(string ouName)
    {
        var principalContext = GetPrincipalContext(ouName);
        var userPrincipal = new UserPrincipal(principalContext);
        return new PrincipalSearcher(userPrincipal);
    }

    public static UserPrincipal GetUserPrincipal(string userName, string ouName)
    {
        var principalContext = GetPrincipalContext(ouName);
        return UserPrincipal.FindByIdentity(principalContext, userName);
    }
}

静的クラスを回避する義務はありません。必要に応じて使用してください。言語設計者がそれらを含めたのには正当な理由があります。
Robert Harvey

5
これらのメソッドをすべて、ヘルパークラスに入れるのではなく、関連付けられたクラスに静的メソッドとして含めなかったのはなぜですか。たとえば、最初のメソッドはPrincipalContextクラスの静的メソッドで、次のように呼び出すことができますPrincipalContext.Get(ouName)。これは本質的にはFactoryメソッドです。
Robert Harvey

@RobertHarvey私がフォローしているとは思いません。このクラスは私のBLLにあり、WebUIの他の多くのクラス(コントローラー)から呼び出されます。また、毎晩のメンテナンスを行うC#コンソールアプリから呼び出され、ヘルパークラスに書き込んだだけで常に再コーディングする必要がありません。
Matthew Verstraete 2016年

5
ソフトウェア開発は常に一連のトレードオフです。どの手法を使用するかは、適用するトレードオフのセットによって異なります。
Robert Harvey

4
@RobertHarvey:PrincipalContextとUserPrincipalはライブラリクラスです
kevin cline

回答:


3

多くの場合、静的クラスはいいと思います。「便利なときに使う」とだけ言っても、あまり役に立ちません。

私の経験則は(いつものように):依存関係を隠していますか?「凝集度が低いことに注意が必要ですが」「ヘルパークラス」が便利だと思われる場合は、ぜひ先に進んでください。ただし、メソッドがグローバル状態にアクセスしないことを確認してください。純粋な静的メソッドは素敵です。一部のグローバルに依存する、またはDB接続を開くか、ディスク/一部の構成ファイルから読み取る静的メソッドは、時限爆弾を刻んでいます。

これらはアプリケーションのテストを非常に困難にします(それを行う唯一の方法は、システム全体を手動で実行することです。または、脆弱な自動フルシステムテストでは、細分性が得​​られません)。また、実装を入れ替えることもできなくなります。

依存関係の逆転の原則とオープン/クローズの原則を覚えておいてください!クラスがプラグ可能であることを確認してください。彼らが薄い空気から物を引っ張らないことを確認してください。それを行う場合は、先に進み、必要なだけ静的メソッドを作成してください!


2

この静的クラスを使用して、Active Directoryへの外部依存関係を隠しているようです。ここでの1つの問題は、これらのメソッドを呼び出すクラスをユニットテストしようとしている場合、静的な呼び出しを偽造できないことです。したがって、すぐにコードのテスト可能性を阻害します。これをIProvideActiveDirectoryInformationのようなインターフェースと、具体的なクラスActiveDirectoryInformationProviderにリファクタリングします。次に、コントローラーのコンストラクターでインターフェイスを渡します。これにより、具象クラスをDIコンテナーに関連付けることができます。また、ActiveDirectoryInformationProviderを偽装して、インターフェースメソッドに必要なものを返すこともできます。

また、インターフェイスでPrincipalSearcherオブジェクトのようなものを渡さないことも検討します。メソッドがGetAllUsersInOU()の場合、ユーザーまたはユーザー名のリストが必要です。


「Active Directoryへの外部依存関係を隠す」という意味がわからない。私はADから読み取りを行います。このクラスは、接続を確立して基本的なデータを取得するために必要なコーディングを削減するために構築されました。
Matthew Verstraete

それが私の言いたいことです。詳細については、Kaiの回答を参照してください。しかし、あなたがやっていることは、あなたのコードをあなたの呼び出しているコードのすべての依存関係に依存させることです。
Fran

1

アプリケーションの抽象概念としてのみ存在するクラスは静的でなければなりません。

たとえば、Twitterのクローンを作成するとします。ツイートには、ユーザーのツイートと広告の2種類があります。どちらも共通の動作を共有しますが、異なります。したがって、ポリモーフィズムとファクトリーを使用して、いずれかを作成します。

それらの2つのつぶやきクラスは、実際のエンティティであるため、具体的なクラスである必要があります。ドメインはこれらのクラスによって定義されます。

ファクトリは静的である必要があります。これは、アプリケーションをより適切に設計し、一種のツイートを作成するコードを再利用できるようにするために、抽象レベルでのみ存在するためです。ドメインは、このファクトリによってどのレベルでも定義されていません。

したがって、クラスをインスタンス化する必要はないが、使用するために拡張する必要がないと考えている場合、それはおそらく静的であるべきであるという良い兆候です。


これは実際には工場のタイプに依存します。簡単なstatic A BuildA() { return new A(); }確認、それは大丈夫です。しかし、Aがインジェクションを必要とする依存関係を持っている場合や、システムの異なる部分が異なるファクトリインスタンス(抽象ファクトリパターン)を必要とする場合など、より複雑なものが必要な場合、静的メソッドはそれをカットしません。
サラ

ご意見ありがとうございます。それはあなたが話しているファクトリーが結局のところ非常に抽象的であるように聞こえません、それはインスタンス化する必要がある具体的なコンセプトであるように見えます(特に、複数の異なるファクトリが必要だと言ったので)。繰り返しになりますが、とにかく何も問題はなく、このテーマについてのアドバイスしかできません。
Steve Chamaillard 16年

1
UserDaoのように、ドメインに変換されない、またはまったく変換されない「純粋な製造」である多くのエンティティが存在します。これは、静的である必要があるかどうかを示すものではありません。作業単位が互いに依存せず、静的である必要があり、拡張可能である必要があります(例:Mathクラス)。
Chris Wohlert、2016年

@ChrisWohlert非常に興味深いコメント(高く評価)ですが、コンテキストのみに依存していませんか?数学に関するアプリでは、Mathクラスをコアクラスの1つにしてインスタンス化できるようにしたいと思っています。UserDaoはユーザー層とDB層の間にある種のリポジトリですか?もしそうなら、なぜインスタンス化したいのですか?「存在」しないため、このためのオブジェクトを作成しなくても、それを注入することができます。どう思いますか?
Steve Chamaillard 16年

1
@SteveChamaillard「実際の」オブジェクトのみをインスタンス化することが理にかなっているという仮定があります。これは、抽象クラス「フルーツ」と継承された「アップル」があり、OOPオブジェクトが実際のオブジェクトを表す場合のOOP 101の類似を思い出させます。しかし、このように制限する必要はありません。OOPはツールであるため、人々は「純粋な
でっちあげ

1

オブジェクト指向プログラミングで提案されていることの1つは悪いです(タイトルはあなたの注意を引くことであり、内容は議論の余地がありますが面白い)*Handler*Managerあり、*Doerクラスは一般に、誰かがオブジェクト指向を手続き型の実装により適している問題。

C#では、プロシージャのモジュール名前空間として静的クラスを使用し、できれば名前を付けることができます。これはその方法だと思いますが、特定のケースではそうではありません。

特定の実装のアプリケーションには、グローバル状態の動作依存関係(特定のユーザーの権限など)があるため、これを使用するコードを個別に単体テストできるように、依存関係を注入する必要があります。


0

何かが足りないかもしれませんが、私の心には答えはメソッドとメンバー変数に要約されます。

これらがすべて静的である場合、クラス自体を静的にすることができます(そうする必要があります)。そうでない場合、それは静的クラスではありません。

注:メソッドと変数がすべて静的であっても、クラスを強制的に静的にするものはありません。


同じことをする同じクラスは、静的でも非静的でも設計できます。常にデザインの選択が必要です。
サラ

設計上の選択があるかもしれませんが、実装はやや恣意的です。メソッドまたはクラスに静的なラベルを付けることを強制するものは何もありません。インスタンス変数がなくても、ReSharperなどの一部のツールはこれを認識します...
Robbie Dee

しかし、すべてのメソッド/メンバーを静的にする必要があるのはいつですか?それが問題です。静的を使用する場合と使用しない場合。
Matthew Verstraete

メンバー変数またはメソッドのいずれもがクラスのインスタンスに依存していない場合-自分には正真正銘の静的クラスがあります。その性質上、これらはヘルパークラスまたはユーティリティなどのようなものになる傾向があります。
ロビーディー

0

使用しているプログラミング言語(C#)を一連のツールとして考えます。

ルールブック、「すべき」、「すべきでない」はありません。

仕事を見て、仕事に最適なツールを選択します。

すべてのスレッドで同じように、グローバルに利用可能なメソッドのコレクションが必要な場合、静的クラスは優れたツールです。(スレッドごとに異なる)クラス内にデータを格納する場合は、おそらくそうではありません。


0

ヘルパークラスに問題はありません。私は、この種のUtilsHelpers、またはHoldersを使用して、さまざまな場所から特定のリソース/ロジックにアクセスできるようにする必要があります。

しかし、私の会社の建築家は、これらのクラスがどこに配置すべきかわからないコードを収集することが多いと繰り返し言っています。また、上層/下層にアクセスしてはならない層からコンポーネントを持ち込むことができ、その責任からタスクを実行するため、彼は嫌いです。また、テスト時にいくつかの問題が発生します。

私は気にしません。私はそれらを使用し、私はそれを使用すべきだと思うのと同じくらい適切に使用しています。そしてそれはうまくいきます。心配しないでください。

ユニットテストの時に、それをあざけるのに苦労することは事実です。しかし、それを行うには少し時間がかかります。この問題が発生するライブラリがあります。

別のアプローチでは、このような欠点(テスト時)を防ぐことができます。たとえば、シングルトンパターン。インスタンスをコンポーネントの依存関係として挿入し、メソッドをインスタンスメソッドに変換します。

とにかく、これまでのところ、私にはあなたの解決策はうまく見えています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.