静的関数とクラス


8

BigDecimals を使用していくつかの基本的な計算を行うためのユーティリティ関数を構築したいとします。たとえば、の平均を計算する関数が必要ですList<BigDecimal>

最善のアプローチは何ですか?静的関数またはユーティリティクラス?

public static BigDecimal computeAverage(List<BigDecimal> numbers)

または

public class BigDecimalUtil

public computeAverage(List<BigDecimal> numbers)

考慮すべきポイントは、どのクラスがこの計算を行う責任があるかを識別することです。この機能は他のクラスではグローバルに必要ではないため、1つのクラスのプライベートメソッドである場合があります。考慮すべきもう1つのことは、静的な定義とスレッドセーフです。
NoChance

回答:


9

おそらく最悪の方法で私のC#学習を提供するつもりですが、ユーティリティクラス内の静的メソッドを常に推奨します。これにより、両方の長所が得られます。オブジェクトをインスタンス化して使用する必要なくアクセスできるメソッドの使いやすさを備えた、クラスの組織的な利点。ユーティリティクラスに時々その動作を変更する理由がある場合は、必要に応じて後で継承/インターフェイスを導入することで、そのようにすることができます。デザインをもう少し移植しやすくしたい場合は、パラダイムが他のオブジェクト指向言語に簡単に移行できることがわかります。


「ユーティリティクラスにその動作を時々変える理由がある場合」:ええ、でも私はJavaショップにいるので、クラスを拡張して静的メソッドを変更することはできません。
S4M、2012

@ S4M当然、メソッドの動作を変更する必要がある場合は、設計を再考する必要があります。ただし、私の回答で述べたように、デザインを変更する必要がある場合は、そのように配置できます。動作を拡張する必要がある場合は、メソッドを常に静的でないようにリファクタリングできます。すべてのメソッドがすべての場所に点在していると、それらを見つけるのが困難になります。当然、メソッドが単一のクラスでのみ必要な場合は、そのクラス内にメソッドを残した方がよいでしょう。その場合、静的であるかどうかの問題は無関係になります。
S.Robins

私自身も静的メソッドの大ファンですが、私の会社では、静的でないメソッドを使用している上級開発者に気づいたので、これが私に考えさせられました。基本的に私はListBigDecimalUtils.computeAverage(x)を実行する一方で、彼は新しいAverageListBigDecimal()。calculate(x)を実行しました。彼のアプローチの利点はわかりません。
S4M、2012

@ S4Mこれにより、クラス内の他の非静的メソッドへのアクセスをメソッドに提供できるようになるだけです。ただし、これらは単に追加のプライベート静的メソッドである可能性があります。より可能性が高いのは、将来の必要性を見た場合に、クラスを拡張するためのオプションを自分に残していることを確認していることです。シニア開発者に、彼のメリットがどこで見られるかを理解したい場合は、彼の理由を尋ねるのがよいでしょう。
S.Robins 2012

@ s4m。単純なその他の静的クラスは問題なく、おそらく今のところ最良の選択だと思います(javaに拡張メソッドが欠けているのは残念です)。しかし、「statsservice」もばかげていません。実行時に平均を平均から中央値に、平均をトリミングに変更する必要があると想像できます。私は、エントロピーを生成し、テスト容易性のためのサービスを必要とするintのリストに対する数学演算を想像できます。
Nathan Cooper、

5

何らかのテーマで接続されたユーティリティ関数を実行したい場合は、それらのクラスを作成し、それらをそのクラスで静的にし、そのクラスのコンストラクターをプライベートにして、誤ってインスタンスを与える可能性を排除します。したがって、2番目のバリアントを使用しますが、コンストラクターは非表示にします。

public class BigDecimalUtil

public computeAverage(List<BigDecimal> numbers)

private BigDecimalUtil(){super();}

もう1つの可能性があります。コンストラクタを作成せずに、このクラスを抽象化することです。ただし、この方法では、クラスのインスタンスを外部だけでなく内部でも使用できません。したがって、この2番目のバリアントは厳しすぎると思います。あなた自身を選択してください。


4

私は@Gangnusに同意します。静的な「ラッパー」クラスは、個々のクラスメソッドが常に分離して使用される場合に意味があり、これはしばしば良い答えになるでしょう。

ただし、関連する計算が一緒に使用される可能性が高い場合は、非静的メソッドを使用して、非静的クラスに何らかの値がある可能性があります。例えば、構築ListStatsUtilしたオブジェクトをList<BigDecimal>コンストラクタに渡され、それがアクセスに便利かもしれないgetStandardDeviationgetVarianceと、getAverageオブジェクト内の背面を通過せずに順番に。これはより洗練されているかもしれませんが、特にオブジェクト内のプライベート状態を共有することによって操作全体で最適化できる計算コストの高い操作が含まれる場合は、パフォーマンスが向上する可能性があります。

public ListStatsUtil {
    private final List<BigDecimal> numbers;
    public ListStatsUtil(List<BigDecimal> numbers) {
        this.numbers = numbers;
    }
    public BigDecimal getAverage() {
        // return average of this.numbers
    }
    public BigDecimal getStandardDeviation() {
        // return std dev of this.numbers
    }
    public BigDecimal getVariance() {
        // return variance of this.numbers
    }
    public BigDecimal getMax() {
        // return max of this.numbers
    }
    public BigDecimal getMin() {
        // return min of this.numbers
    }
}

この新しいプログラマーサイトでは、@ Gangnusにコメントを残す権限がまだないので、ここに残しておきます。んsuper()プライベートコンストラクタでは、Javaで静的クラスの意味をなさない?
codeoutloud

間違いなく、それは将来の急進的なリファクタリングの場合の自己規律としてのみ意味があります。このコンストラクターは実行しないでください。
Gangnus

分からない。これらすべての関数は、getVarianceなどとして、List <BigDecimal>を取り、doubleのBigDecimalを返します。どのようにしてそれらをチェーンに入れることができますか?ユーティリティをチェーンするという考えは良いですが、a)あなたが提供するケースには適していません。b)どちらが問題であるかはわかりません。ユーティリティを持つ新しいクラスが必要な場合のためです。したがって、そのような質問は決して発生しません-答えは明白です。
Gangnus

チェーンではなく、単一のリストで複数の操作が必要になる場合があるだけです。質問はこの可能性を排除しなかった。
codeoutloud

私が説明したクラスは、そのようなメソッドを簡単に定義できます。インスタンスを出力しないだけで、OK内で使用できます。この場合はもちろん、コンストラクターが機能するものになりますが、準備は整っていますね。:-)
Gangnus

1

私はコーディングアウトラウドの回答に投票しましたが、少し拡張したいと思います。

クラスでコレクションをラッピングすることは、私がいつもやろうとしていることです。私のルールは、「ネイキッドコレクションを絶対に通過させないこと」です。私が見たOOの最大の失敗は、所属するメソッドを追加することを人々が恐れている場合です。あなたの場合、メソッドはコレクションに属します(考えれば明らかですが)、それらをコレクションにラップしてそこに配置し、アイシングをケーキに配置するには、必要な機能のみを新しいクラスの外部に公開します(codingoutloudとして)そうしたので、あなたはあなたの単一の小さなクラスを見て、そのコレクションを操作するすべてのものを簡単に理解することができます。

すべてのコードであるため、考えられるすべての問題を解決する必要はありません。コレクションラッパーは、それとやり取りする他のクラスを編集するのと同じくらい簡単に編集できます。これにより、必要に応じて他のコードをクラスに取り込むことができます。コレクションを公開しないと、ラッパーに属するコードがすぐにわかります。

これにより、コレクションを完全に制御できるため、コレクションの機能と矛盾する状態になるのを防ぐことができます(たとえば、コレクションのエントリがnullになり得ない場合は、誰かがnullを入力できないようにするだけです!)

私が今まで見た悪いOOコードのほとんどは、変更可能な独自のコードで問題のオブジェクトをラップするのではなく、コードを追加できないオブジェクトに属する静的ユーティリティまたはインラインコードを作成することを選択したために作成されました。


この特定のケースでは、平均は任意の数のコレクションを呼び出すための合理的な方法でした。つまり、もう少し多くの機能を使用して、すべての番号コンテナーに新しい名前を付けるだけで済みます。努力に対する見返りが悪いようです。これは、c#の拡張メソッドが使用するもので、Javaでは静的に行き詰まっています。
Nathan Cooper

多くの場合、ビジネスロジックのないユーティリティには適切なOOソリューションがありません。できる最善の方法は、静的クラスと、コレクションなどの固定クラスです。本当に汎用ユーティリティを実行する必要がある場合は、コレクション、math util、その他すべてのユーティリティのようにooを放棄することもできます。この場合、彼はおそらくビジネスコードに1つのコレクションを使用しているだけなのに、なぜ一般的なソリューションを実装するのでしょうか。
ビルK

0

私が間違っておらず、Javaが純粋なOO言語であり続けるなら、クラスでそれらをラップせずに関数を作成することはできません。

だからあなたの答えは:Mathクラスとは異なり、どちらも静的ユーティリティクラスにラップされた静的関数です。


-2

注入されたCalcAverageStrategyインターフェースはどうでしょうか。そうすれば、必要に応じて平均/中央値/モードの実装を注入できます。

各実装はテストが簡単で、テスト用にモックするのも簡単です。


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