私は過去数時間を費やしてstatic
クラスの使用について調べ、それらを使用する必要があるかどうかを理解しようとしましたが、それでも何らかの結論には至っていません。議論はどちらにでも行くことができるようです。私のアプリケーションでは、非常に一般的なタスクを実行し、アプリケーション(ASP.Net MVC
Webアプリケーション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);
}
}
多くの場合、静的クラスはいいと思います。 「便利なときに使う」とだけ言っても、あまり役に立ちません。
私の経験則は(いつものように):依存関係を隠していますか? 「凝集度が低いことに注意が必要ですが」「ヘルパークラス」が便利だと思われる場合は、どうぞ先に進んでください。ただし、メソッドがグローバル状態にアクセスしないことを確認してください。純粋な静的メソッドは素敵です。一部のグローバルに依存する、またはDB接続を開くか、ディスク/一部の構成ファイルから読み取る静的メソッドは、時限爆弾を刻んでいます。
これらはアプリケーションのテストを非常に困難にします(それを行う唯一の方法は、システム全体を手動で実行するか、または脆弱な自動フルシステムテストを使用すると、細分性が得られません)。また、実装を入れ替えることもできなくなります。
依存関係の逆転の原則とオープン/クローズの原則を覚えておいてください!クラスがプラグ可能であることを確認してください。彼らが薄い空気から物を引っ張らないことを確認してください。それを行う場合は、先に進み、必要なだけ静的メソッドを作成してください!
この静的クラスを使用して、Active Directoryへの外部依存関係を隠しているようです。ここでの1つの問題は、これらのメソッドを呼び出すクラスをユニットテストしようとしている場合、静的呼び出しを偽造できないことです。したがって、すぐにコードのテスト可能性を阻害します。これをIProvideActiveDirectoryInformationのようなインターフェイス、および具象クラスActiveDirectoryInformationProviderにリファクタリングします。次に、コントローラーのコンストラクターでインターフェイスを渡します。これにより、具象クラスをDIコンテナーに関連付けることができます。また、ActiveDirectoryInformationProviderを偽造して、インターフェイスメソッドに必要なものを返すこともできます。
また、インターフェイスのPrincipalSearcherオブジェクトなどを返さないことも検討します。メソッドがGetAllUsersInOU()の場合、ユーザーまたはユーザー名のリストが必要です。
アプリケーションの抽象概念としてのみ存在するクラスは静的でなければなりません。
たとえば、Twitterのクローンを作成するとします。ツイートには、ユーザーのツイートと広告の2種類があります。どちらも共通の動作を共有しますが、動作は異なります。したがって、ポリモーフィズムとファクトリーを使用して、いずれかを作成します。
それらの2つのつぶやきクラスは、実際のエンティティであるため、具体的なクラスである必要があります。ドメインはこれらのクラスによって定義されます。
ファクトリは静的である必要があります。これは、アプリケーションをより適切に設計し、タイプのツイートを作成するコードを再利用できるようにするために、抽象レベルでのみ存在するためです。ドメインはこのファクトリによってどのレベルでも定義されていません。
したがって、クラスをインスタンス化する必要はないが、使用するために拡張する必要がないと思われる場合は、静的である必要があることを示しています。
Object-Oriented Programming is Bad (タイトルはあなたの注意を引くためのものであり、内容は論争ですが面白い)で提案されていることの1つは*Handler
、*Manager
および*Doer
クラスは一般に、手続き型の実装により適した問題にオブジェクト指向を強制しようとしている誰かを示すコードのにおいです。
C#では、プロシージャのモジュール名前空間として静的クラスを使用し、できれば名前を付けることができます。これはその方法だと思いますが、あなたの特定のケースではそうではありません。
特定の実装のアプリケーションには、グローバル状態の動作依存関係(特定のユーザーのアクセス許可など)があるため、これを使用するコードを個別に単体テストできるように、依存関係を注入する必要があります。
何かが足りないかもしれませんが、私の心には答えはメソッドとメンバー変数に要約されます。
これらがすべて静的である場合、クラス自体を静的にすることができます(そうする必要があります)。そうでない場合は、静的クラスではありません。
N.B. forcesメソッドと変数がすべて静的であっても、クラスが静的であることはありません。
使用しているプログラミング言語(C#)を一連のツールとして考えます。
ルールブック、「すべき」、「すべきでない」はありません。
仕事を見て、仕事に最適なツールを選択します。
すべてのスレッドで同じように、グローバルに利用可能なメソッドのコレクションが必要な場合、静的クラスは優れたツールです。 (スレッドごとに異なる)クラス内にデータを格納したい場合は、おそらくそうではありません。
ヘルパークラスに問題はありません。この種類のtils、HelpersまたはHoldersを使用して、別の場所から特定のリソース/ロジックにアクセスできるようにする必要があります。
しかし、私の会社の建築家は、これらのクラスがどこに配置すべきかわからないコードを収集することが多いと繰り返し言っています。また、上層/下層にアクセスすべきではない層からコンポーネントを持ち込むことができ、その責任からタスクを実行するため、彼は嫌いです。また、テスト時にいくつかの問題が発生します。
私は気にしません。私はそれらを使用し、使用すべきだと思うのと同じくらい適切に使用しています。そしてそれはうまくいきます。心配しないでください。
ユニットテストの時に、それをあざけるのに苦労することは事実です。しかし、それを行うには少し時間がかかります。この問題が発生するライブラリがあります。
別のアプローチでは、このような欠点(テスト時)を防ぐことができます。たとえば、シングルトンパターン。インスタンスをコンポーネントの依存関係として挿入し、メソッドをインスタンスメソッドに変換します。
とにかく、これまでのところ、私にはあなたの解決策はうまく見えています。