ステートレスについての意味的な手がかりとしての「静的」?


11

私は最近、Javaの中規模プロジェクトをリファクタリングして、戻って単体テストを追加しました。シングルトンとスタティックをモックするのがどれほど苦痛であるかに気付いたとき、私はついにこれまで読んでいたものをついに「手に入れました」。(私は経験から学ぶ必要がある人の一人です。まあ。)

ですから、Springを使用してオブジェクトを作成し、それらをワイヤリングするようになったのでstatic、左右のキーワードを取り除きました。(潜在的にそれをモックしたい場合、Math.abs()と同じ意味で本当に静的ではありませんよね?)問題は、staticメソッドが依存していないことを示すために使用する習慣になったことです任意のオブジェクト状態。例えば:

//Before
import com.thirdparty.ThirdPartyLibrary.Thingy;
public class ThirdPartyLibraryWrapper {
    public static Thingy newThingy(InputType input) {
         new Thingy.Builder().withInput(input).alwaysFrobnicate().build();
    }
}

//called as...
ThirdPartyLibraryWrapper.newThingy(input);
//After
public class ThirdPartyFactory {
    public Thingy newThingy(InputType input) {
         new Thingy.Builder().withInput(input).alwaysFrobnicate().build();
    }
}

//called as...
thirdPartyFactoryInstance.newThingy(input);

だから、ここが微妙な感覚になります。古い方法が好きだったのは、Math.sin(x)と同様に、ThirdPartyLibraryWrapper.newThingy(x)が毎回同じ方法で同じことをしたことを大文字が教えてくれたからです。オブジェクトに要求することをオブジェクトがどのように行うかを変更するオブジェクトの状態はありません。ここで私が検討しているいくつかの可能な答えがあります。

  • 誰もこのように感じていないので、私には何か問題があります。たぶん、オブジェクト指向のやり方を実際に内部化していないだけかもしれません!たぶん私はJavaで書いていますが、FORTRANなどで考えています。(私がFORTRANを書いたことがないので、どれが印象的でしょう。)
  • コードについての推論を目的として、不変性の一種のプロキシとして静的性を使用しているのかもしれません。そうは言っても、ステートフルなものとそうでないものを知るためにコードを維持するために、コードに手がかり ありますか?
  • おそらく、良いオブジェクトのメタファーを選択した場合、これは無料で提供されるはずです。例えばthingyWrapperThingyそれ自体が可変である可能性のあるラップされた状態に依存していないように聞こえます。同様に、thingyFactoryサウンドは不変である必要がありますが、作成時に選択されるさまざまな戦略を持つことができます。

回答:


12

古い方法が好きだったのは、Math.sin(x)と同様に、ThirdPartyLibraryWrapper.newThingy(x)が毎回同じ方法で同じことをしたことを大文字が教えてくれたからです。オブジェクトに要求することをオブジェクトがどのように行うかを変更するオブジェクトの状態はありません。

それが正しい方法です、はい。それは、言ったstatic不変または状態の持続の保証を付与しません。そのような保証の提案としてそれを使用することは理にかなっていますが、決して保証されません。

以下を考慮してください。

public static class Logger
{
    public static int LogLevel { get; set; }

    public static void Log(string message, int logLevel)
    {
        if (logLevel >= LogLevel)
        {
            // logs the message, but only if it is important enough.
        }
    }
}

このクラスは状態を保持するだけでなく、Logger.Log()状態が変更されるとメソッドの動作が変更されます。これはstaticクラスパターンの完全に正当な演習ですが、提案しているセマンティックの保証はありません。


あなたは私の直感の基礎に有用な対抗点を提示するため、チェックマークを付けましたが、コーディングによる状態の欠如と副作用の欠如に関するその契約/期待をどのように表現すべきかについて、あなたの考えを取得したいです慣習。
レオガー

1
通常、そのような期待はメソッドのドキュメントに含まれています。同じことがスレッドセーフにも当てはまります。
ロバートハーヴェイ

5

私の意見では、あなたが言っていること-すべての静的関数は無効である-ほとんどの場合、コードを書くための良いオブジェクト指向の方法ですが、静的関数を見たときに、副作用がないと自動的に仮定するべきではないと思います。状況はより複雑になる可能性があります。たとえば、Class.forName(String)ステートレスであるように見えるが実際にクラスをメモリにロードし、最終的に静的フィールドをインスタンス化する/静的イニシャライザを実行する関数を取り上げます。これはi等関数の例です(最初の関数の後の呼び出しは違いはありません)が、純粋な関数ではありません(副作用がないとは言えません)。これも良い選択ですが、同じ関数への3つの異なる呼び出しが3つの異なる結果をもたらす場合があります。たとえば、あなたが電話した場合Thread.currentThread() マルチスレッドアプリケーションでは、毎回同じスレッドを受け取る保証はありません。

そうは言っても、何がステートフルで何がステートフルでないかを知るためにコードを維持するためにコードに何の手がかりが必要ですか?

適切な解決策は、文書化することです(Javadocなど)。また、関数の名前とその機能から、静的関数は純粋な関数であると推測できます。たとえば、誰かがAssert.assertTrue(boolean)JUnitからどこかで何らかの状態を変えると信じる理由はありません。一方、次のような関数System.clearProperty(String)が呼び出されると、副作用があることは明らかです。


「無能」と「ステートレス」の違いは何ですか?
Pacerier

@Pacerier違いはないはずです。
m3th0dman

4

そうは言っても、何がステートフルで何がステートフルでないかを知るためにコードを維持するためにコードに何の手がかりが必要ですか?

それらを静的にすることができます。C#の世界でFxCopを使用すると、メンバー変数を参照しないものを静的にすることができます。これが正しいことです(通常)。

シングルトンとスタティックをモックするのがどれほど苦痛であるかに気付いたとき、私はついにこれまで読んでいたものをついに「手に入れました」。

それらをすべてインスタンスに移動することは、おそらく正しいアプローチではありません。代わりに、静的メソッドの依存関係を、それらを使用するクラスから分離します。静的メソッドを単独でテストし、テストが必要なときにコンシューマの依存関係を置き換えることができます。


「静的メソッドへの依存関係の分離」の例を描くことができますか?何をアクティベートしているのか明確ではありません。静的メソッドで実装の詳細を既に非表示にしています。結局のところ、それを使用するクラスその機能に到達する必要があります。すべての静的メソッドの薄いラッパーを持つインスタンスオブジェクトを作成する必要があると言っていますか?
レオガー

1
@leoger-静的メソッドを使用するクラスは、そのクラスをテストしている場合、機能に到達する必要はありません。そうでなければ、静的メソッドをモックすることはありません。
Telastyn
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.