「純粋な関数」ではなく、外部APIまたはハードウェアと相互作用するメソッドは静的である必要がありますか?


8

メソッドを静的にするかどうかについて読んだとき、この投稿要約されているように、メソッドは状態を変更せず、結果がそれ。ただし、この投稿で最も投票数の多い回答には可能な限り静的メソッドを使用する必要があると記載されています。この投稿の回答の多くは、最も論理的なことは何でもすべきだと言っています。

私の場合、複数の場所で使用され、どのモデルまたはビューモデル(C#MVVMを使用)のメンバーとしても意味がないため、共通のユーティリティクラスに〜15のメソッドがあります。パッケージを使用してさまざまなハードウェアコンポーネントと対話するvoidメソッドがあります(たとえば、National Instruments、OPCクライアントなど)。一部の入力を取得し、APIに対してGETまたはPUTを実行してから応答を返すメソッドもあります。これらのメソッドはHttpClientまたは類似のものを使用します。これらのメソッドは、のような入力に対する単純な演算子ではなくMath.Sqrt()、状態を変更しません。

それで、そのようなメソッド(そしてこの場合、クラス全体)は静的でなければなりませんか?静的メソッドを持つ静的クラスがあることには明らかな利点があります。オブジェクトを作成する必要がないため、安全で高速です。また、これらの静的メソッドはそれぞれ、APIとハードウェアの相互作用のためにより多くの静的メソッドとクラスを使用します。私が目にする唯一の欠点は、TypeMock Isolatorのような有料のフレームワークで単体テストを書かなければならないことです。TypeMock Isolatorなどの有料サービスを使用してモックを作成するのが答えである場合、コストは問題になりません。コンセンサスであればそれで結構です。新しい開発者を獲得したり、プロジェクトが成長したりするときに、適切にスケーリングし、技術的な負債をほとんど残さない決定をしたいだけです。

これをより明確にするためにさらに情報を提供する必要があるかどうかをお知らせください!


3
「さまざまなハードウェアコンポーネントとやり取りする」、「入力を取得し、APIにGETまたはPUTを実行してから応答を返すメソッドもあります」->これらは、状態とやり取りするポスターの子の例
Caleth

2
@Calethのコメントを拡張するには:「状態」はメモリ内の1と0に適用されるだけではないことに注意してください。ロボットの腕を動かす関数を呼び出すと、実際の状況では、状態が変化し、そうすることによるすべての影響が生じます。
Greg Burghardt

1
「オブジェクトを作成する必要がないため、安全で高速です」。ネットワークAPIの場合は、呼び出し内に多くのオブジェクト作成しています。また、いずれの場合でも、オブジェクトの作成にかかる時間は、ネットワーク遅延に比べて短いです。
user949300


同じハードウェアコンポーネントが複数ある場合はどうしますか?すべてのメソッドをコピー/貼り付けますか?
user253751

回答:


15

それで、そのようなメソッド(そしてこの場合、クラス全体)は静的でなければなりませんか?

いいえ。または、少なくとも、これらを静的変数として直接使用しないでください。

さまざまなハードウェアコンポーネントを使用している場合、それらを模擬し、新しいものを使用し、使用しているものを選択する可能性が非常高くなります。すべてのインターフェイス(または他の抽象化)があることを叫ぶので、残りのコードは、ハードウェアコンポーネントがあることをすぐに無視できます。また、ほとんどの言語の静力学は、インターフェース(およびその他の抽象化メカニズム)との連携が不十分です。


1
または、少なくとも、外部のものと通信する実際の呼び出しを行う静的メソッドのコレクションを持っているのが一般的ですが、その上にステートフルAPIクラスを構築し、そのクラスを物事を成し遂げる方法として公開します。基礎となるインターフェース、つまりファサードパターンではなく、モックされるのはそのクラスです。
whatsisname

返信いただきありがとうございます!これはコンセンサスのようですので、今後はこの原則を遵守します。
adjordan

4

あなたが読んだすべての矛盾するアドバイスはある意味では理にかなっていますが、それらはすべて(異なる)仮定や曖昧な表現をしています。それは、「同じことを別の言葉で言う」タイプの区別の1つです。

メソッドは、状態を変更しない場合にのみ静的でなければなりません

「状態の変更」のあいまいさに注意してください。次の例はこのルールに(文字通り)違反していますが、ルールの(比喩的な)精神を保持しています。

public static void SetUserNameToBob(User u)
{
    u.Name = "Bob";
}

これはUserオブジェクトの状態を変更するため、実際には「状態を変更」します。

ただし、このメソッドは、それ自体の論理フローを決定するために特定の内部状態に依存しません(たとえばu.Name = currentlySelectedDefaultName()、選択された名前が選択された状態であるため、違反になります)。そして、それが意味するところだと思います。内部状態は変更されません。

[メソッドは静的でなければなりません]その結果は、提供されたパラメーターにのみ依存します

前の項目を見てください、これはほとんど同じことを言っています。それが意味することはこれです:

public static string currentlySelectedDefaultName; 
public static void SetUserNameToBob(User u)
{
    u.Name = currentlySelectedDefaultName;
}

「現在のデフォルト」の名前は状態であるため、静的であってはならず、グローバル変数/メソッドであってはなりません。

2つの別々のスレッドが実行されている場合にどうなるかを考えてみます。1つはデフォルトで「Bob」に、もう1つはデフォルトで「Jim」にしたい場合です。それらは最終的に、大きなデバッグの問題や予期しない動作を引き起こす可能性がある値をめぐって争うことになります。
ただし、すべてのスレッドに独自のDefaultNameSetterオブジェクトがある場合、それらは同じリソースをめぐって争うことはありません。

ただし、この投稿で最も投票数の多い回答には、可能な限り静的メソッドを使用する必要があると記載されています。

これは、try / failによるルールの強制のようなものです。このメソッドを静的に設定できますか?

  • はい=>グッド!そのままにしている!
  • いいえ=>これは、コードがどこかで非静的な値に依存しているため、静的にしないでください。

ジュラシックパークジェフゴールドブラムを間接的に引用するには、それが可能であること証明するだけで何かをする必要性を主張するべきではありません。

繰り返しになりますが、アプローチは必ずしも(または常に)間違っているわけではありませんが、メソッドはすでに論理的に可能な限り状態にとらわれないように記述されていると盲目的に仮定しています。

この方法論的アプローチに同意しても、プロジェクトが開発中でなくなった場合にのみ適用できます。プロジェクトがまだ開発中の場合、現在の方法が将来の実装のプレースホルダーになる可能性があります。Foo()状態依存ロジックがまだ実装されていない場合、今日は静的にすることは可能ですが、明日は不可能にすることができます。

この投稿の回答の多くは、最も論理的なことは何でもすべきだと言っています。

まあ、彼らは間違っていません。しかし、これは「正しいことをする」と言っただけの小さな言い回しではありませんか?静的をいつ使用し、いつ静的を回避するかを既に知っているのでない限り、これは本当に役立つアドバイスではありません。キャッチ22です。


では、いつ静的を使用する必要がありますか?

お気づきのように、誰もがルールに同意するわけではなく、少なくともルールの言い回しに同意するわけではありません。ここで別の試みを追加しますが、これが別の標準を効果的に作成していることに注意してください。

ここに画像の説明を入力してください

心に留めておきます。

静力学は普遍的な真実です。

それがグローバル名前空間の目的です。アプリケーション層全体で正しいことです。

ここには滑りやすい議論があります。いくつかの例:

var myConfigKey = ConfigurationManager.AppSettings["myConfigKey"];

これは非常に明確な例です。アプリケーション構成は本質的に構成がアプリケーションに対してグローバルであることを意味するため、統計方式が保証されます。

bool datesOverlap = DateHelper.HasOverlap(myDateA_Start, myDateA_End, myDateB_Start, myDateB_End);

この方法は普遍的に正しいです。それは気にしないそのあなたが比較している日付。メソッドは日付の意味を気にしません。それらが雇用日であるか、契約日であるかどうかは...メソッドのアルゴリズムには関係ありません。

コンテキスト駆動型状態駆動型の意味的な類似性に注意してください。どちらのソートも「非ユニバーサル」状態を指します。したがって、コンテキストの違いは状態に依存し、静的にするのには適していません。

var newPersonObject = Person.Create();

これは普遍的な真実です。同じ作成プロセスがアプリケーション全体で使用されます。

ただし、この線は不鮮明になる可能性があります。

var newManager = Person.CreateManager();
var newJanitor = Person.CreateJanitor();

技術的な観点からは、何も変わっていません。マネージャー(および管理人)は、アプリケーション全体で同じ方法で作成されます。ただし、これにより微妙に状態(マネージャー/管理人)が作成され、真実の普遍性が徐々に、しかし着実に損なわれます。

できますか?技術的な観点から。はい
それを行うべきですか?それはあなたが純粋な原則を主張しているのか、それとも論理的完全性を無意味に追求しないようにするために妥協が必要であることを考慮に入れているのかという問題です。だから私は言うでしょう、それは問題を解決するためになされたものよりも、より大きな問題を作成しない場合

オプションが拡大するにつれて(マネージャー、管理人、会計士、営業担当者など)、問題は大きくなります。十分に大きな問題の場合は、工場パターンが望ましいです。

オプションが2つしかなく、オプションのリストが増えると疑う理由がない場合は、静的作成メソッドで十分であると主張できます。反対する人もいるかもしれませんが、私も彼らの主張を理解しています。しかし、私は実践的であり、私のアプローチでは過度に完璧主義的ではありません。


3

ただし、この投稿で最も投票数の多い回答には、可能な限り静的メソッドを使用する必要があると記載されています...

直接結合されている状態に影響を与える静的メソッドは非常に悪い考えです。それらは、グローバルな状態-「遠くでの不気味な行動」-問題、スパゲッティコードなどにつながります。テスト、デバッグ、保守が困難です。最も賛成された答えの私の読書はこれのどれも励ましません、従ってすべては元気です。

それで、そのようなメソッド(そしてこの場合、クラス全体)は静的でなければなりませんか?

場合によります。「パッケージを使用してさまざまなハードウェアコンポーネントとやり取りするvoidメソッド」の例を見てみましょう。これらのメソッドは静的にすることができますが、これらのメソッドがそれらのパッケージから分離されている場合に限ります。これを実現する1つの方法は、これらのパッケージをパラメーターとして渡すことです。ハードウェアなしでメソッドをテストしたいですか?簡単です。パラメータを介してハードウェアにアクセスするのではなく、アクションを記録するダミーの模擬パッケージを渡します。同じことがHTTPメソッドにも当てはまります。APIにアクセスする実際の手段も同様にパラメーターとして渡される限り。

しかし、インスタンスを作成し、それらのパッケージ、HTTPクラスなどを構築時に注入することで、この方法で本当に何かを達成していますか?おそらく違います。もちろん、これらは静的メソッドなので、インスタンスは必要ありません。しかし、それらをパラメーターとして渡すために、コード全体にそれらのパッケージなどをすべて公開する必要があるという複雑さが追加されます。多くの場合、単一のインスタンスを作成してそれを渡す方がはるかに簡単です。


私が作成した「UtilityMethods.cs」クラスの単一インスタンスを渡すように言っているのですか?現在、SimpleIoCで依存関係注入を使用していますが、これは同じ考えです。
adjordan

2
@adjordan、確かに。純粋な(貧しい人の)DIを使用するか、IoCフレームワークを使用して注入を支援するかは、あなた次第です。原理は同じですIUtilityMethods。静的関数に渡す必要のある複数のインスタンスを渡すよりも、インスタンスを渡すだけの方が簡単です。
David Arno

1

私がチームで使用しているのは、静的メソッド/クラスが本当に必要な場合に使用することです。静的メソッド/クラスを使用する最初のオプションであってはなりません。それはそのための非常に正当な理由でなければなりません。多くの開発者は、静的オプションの方が高速で安価であることを理解しています。しかし、それはおそらく最初の段階です。コストは、より複雑な単体テストを構築し、複数の実装でコントラクト(インターフェイス)を使用する機能がないことです。ハードウェアと相互作用するメソッド/クラス用。これらは静的であってはなりません。まず、ほとんどの場合、理由はありません。次に、ユニットテストでこれらのクラスをモックして、より簡単なテストコードを作成する必要があります。第三に、将来、実装を置き換えることが可能です。


0

静的関数は、複数のアクセスを並行して許可したい場合により困難です。

たとえば、複数のHTTP呼び出しを同時に実行できるようにすることは、完全に合理的であり、おそらく良いアイデアです。インスタンスオブジェクトを使用すると、これらの呼び出しのさまざまな状態(ヘッダー、結果コード、バッファーなど)を簡単に維持できます。

単一の静的メソッドでは、その状態を保持するための内部インスタンスを作成してしまう可能性があります。または、エラーが発生しやすいすべてを同期します(私はJava用語、YMMVを使用しています)。または、キューを使用します。いずれにせよ、派手なフットワークがなければ、並行して実行する能力を失います。ネットワークの不具合により1つのHTTPコールが停止した場合、他のすべてのコールは待機する必要があります。

ハードウェアについても同じです。場合によっては、並列アクセスを許可する方が理にかなっていることがあります。

これらの理由で、私はあなたが引用した8歳の回答に同意しません。


4
静的関数は状態をまったく含むべきではありません。
Pieter B

1
@Pieter Bもちろん(おそらくカウンター以外)。HTTPの例では、状態を保持するために、呼び出しごとにMyHTTPHelperオブジェクトを作成する必要があります。この時点では、静的メソッドをまったく使用せずに、元の呼び出し元にオブジェクトを作成させる方がおそらく簡単です。
user949300 2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.