web-dev-qa-db-ja.com

ユーティリティクラスは悪ですか?

このスレッドを見ました

「ユーティリティ」クラスが悪の場合、汎用コードはどこに配置しますか?

そして、なぜユーティリティクラスは悪なのでしょうか?

数十クラスの深さのドメインモデルがあるとしましょう。インスタンスをxml-ifyできるようにする必要があります。親でtoXmlメソッドを作成しますか? MyDomainXmlUtility.toXmlヘルパークラスを作成しますか?これは、ビジネスニーズがドメインモデル全体に​​及ぶ場合です。実際にインスタンスメソッドとして属しているのでしょうか。アプリケーションのxml機能に多数の補助メソッドがある場合はどうでしょうか?

82
hvgotcodes

ユーティリティクラスは必ずしも悪ではありませんが、優れたオブジェクト指向設計を構成する原則に違反する可能性があります。優れたオブジェクト指向設計では、ほとんどのクラスは単一の物とそのすべての属性と操作を表す必要があります。 Thingを操作している場合、そのメソッドはおそらくそのThingのメンバーである必要があります。

ただし、ユーティリティクラスを使用して多数のメソッドをグループ化できる場合があります。たとえば、Java.util.Collectionsクラスは、任意のJavaコレクションで使用できる多数のユーティリティを提供します。これらは特定のコレクションタイプに固有ではなく、任意のコレクションで使用できるアルゴリズムを実装します。

本当に、あなたがする必要があるのは、あなたのデザインについて考え、メソッドを置くのが最も理にかなっている場所を決定することです。通常、それはクラス内の操作としてです。ただし、実際にはユーティリティクラスとしての場合もあります。ただし、ユーティリティクラスを使用する場合は、単にランダムなメソッドをその中にスローするのではなく、目的と機能ごとにメソッドを整理します。

109
Thomas Owens

一般的なコンセンサスは、ユーティリティクラスは悪ではないということだと思います本質的に。慎重に使用する必要があります。

  • 静的ユーティリティメソッドを一般的かつ再利用可能に設計します。それらがステートレスであることを確認してください。つまり、静的変数はありません。

  • ユーティリティメソッドがたくさんある場合は、開発者が簡単に見つけられるように、それらをクラスに分割します。

  • ドメインクラスの静的メソッドまたはインスタンスメソッドがより良い解決策となる場合は、ユーティリティクラスを使用しないでください。たとえば、抽象基本クラスまたはインスタンス化可能なヘルパークラスのメソッドがより良いソリューションであるかどうかを検討します。

  • Java 8以降では、インターフェースの「デフォルトメソッド」がユーティリティクラスよりも優れたオプションである可能性があります。


この質問を見るもう1つの方法は、引用された質問で"ユーティリティクラスが"悪 "である場合"がストローマンの引数であることを観察することです。それは私のように尋ねます:

「豚が飛べるなら、傘を持っていくべきですか?」.

上記の質問で、私は実際に豚が飛ぶことができると言っているわけではありません...または、彼らがcould flyという命題に同意しているとは言いません。

典型的な"xyz is evil"ステートメントは、極端な視点を向けることで考えさせるための修辞的なデバイスです。それらは、文字通りの事実の記述として意図されることはほとんどありません。

52
Stephen C

ユーティリティクラスは、それらをサポートするデータの責任をグループ化できないため、問題があります。

しかし、それらは非常に便利であり、私はそれらを永続的な構造として、またはより徹底的なリファクタリング中の踏み台として常に構築しています。

クリーンコード パースペクティブから、ユーティリティクラスは単一責任とオープンクローズド原則に違反します。それらには変更する理由がたくさんあり、設計上は拡張できません。それらは本当にリファクタリング中に中間のクラフとして存在するべきです。

12
Alain O'Dea

悪になり始めると思う

1)大きすぎる(この場合、意味のあるカテゴリにグループ化するだけです)。
2)静的メソッドであってはならないメソッドが存在する

しかし、これらの条件が満たされない限り、それらは非常に役立つと思います。

7
Enno Shioji

経験則

この問題は次の2つの観点から見ることができます。

  • 全体 *Utilメソッドは、多くの場合、不適切なコード設計または遅延命名規則の提案です。
  • これは、再利用可能なクロスドメインステートレス機能のための正当な設計ソリューションです。ほとんどすべての一般的な問題には、既存の解決策があることに注意してください。

例1. utilクラス/モジュールの正しい使用法。外部ライブラリの例

あなたがローンとクレジットカードを管理するアプリケーションを書いていると仮定しましょう。これらのモジュールからのデータは、json形式でWebサービスを通じて公開されます。理論的には、オブジェクトをjsonにある文字列に手動で変換できますが、それは車輪を再発明するでしょう。正しい解決策は、Javaオブジェクトを目的の形式に変換するために使用される外部ライブラリを両方のモジュールに含めることです。(画像例では gson

enter image description here


例2. utilクラス/モジュールの正しい使用法。他のチームメンバーに言い訳せずに独自のutilを書く

ユースケースとして、2つのアプリケーションモジュールでいくつかの計算を実行する必要があると仮定しますが、どちらもポーランドで祝日があることを知る必要があります。理論的には、これらの計算はモジュール内で行うことができますが、この機能を抽出して別のモジュールにする方が良いでしょう。

これは小さいですが、重要な詳細です。あなたが書いたクラス/モジュールはHolidayUtilではなくPolishHolidayCalculatorと呼ばれます。機能的にはutilクラスですが、一般的なWordを避けることができました。

enter image description here

4
Marcin Szymczak

ユーティリティクラスが悪であることに完全には同意しません。

ユーティリティクラスは何らかの方法でOOプリンシパルに違反する可能性がありますが、必ずしも悪いわけではありません。

たとえば、値xに一致するすべての部分文字列の文字列を消去する関数が必要だと想像してください。

stl c ++(現在)は、これを直接サポートしていません。

std::stringの多相拡張を作成できます。

しかし問題は、プロジェクトで使用するすべての文字列を拡張文字列クラスにしたいのですか?

OOが本当に意味をなさない場合があります。これはその1つです。私たちのプログラムが他のプログラムと互換性があるようにしたいので、std::stringクラスStringUtil_(または何か)を作成します。

クラスごとに1つのユーティリティを使用するのが最善だと思います。すべてのクラスに対して1つのユーティリティを使用するか、1つのクラスに対して多くのユーティリティを使用するのはばかげていると思います。

3
HumbleWebDev

この質問を今振り返ってみると、C#拡張メソッドはユーティリティクラスの必要性を完全に破壊していると思います。しかし、すべての言語にこのような天才的な構造があるわけではありません。

JavaScriptもあり、既存のオブジェクトに新しい関数を追加するだけです。

しかし、C++のような古い言語でこの問題を解決するエレガントな方法が本当にあるかどうかはわかりません...

Good OOコードは書くのが難しく、Good OOを書くにはまともな機能コードを書くよりも多くの時間/知識が必要です。

そして、予算が限られているとき、上司はあなたが一日中たくさんのクラスを書いて過ごしたことをいつも喜んでいるとは限りません...

3
HumbleWebDev

ユーティリティクラスは、クラスのより良い名前を考え出すのが面倒だからです。

そうは言っても、私は怠け者です。仕事を終わらせる必要があるだけで、心が空いている場合があります。「ユーティリティ」クラスが忍び寄るときです。

3
Larry Watanabe

デザイナーがコードを置く適切な場所を考えることができなかったという理由だけで、何かをユーティリティとブランド化することは非常に簡単です。多くの場合、真の「ユーティリティ」はほとんどありません。

経験則として、私は通常、最初に使用するパッケージにコードを保持し、その後、後で他の場所で本当に必要であることがわかった場合にのみ、より一般的な場所にリファクタリングします。唯一の例外は、類似または関連する機能を実行するパッケージが既にあり、そこに最適なコードがある場合です。

2
mdma

ステートレスな静的メソッドを含むユーティリティクラスが役立つ場合があります。多くの場合、これらは単体テストが非常に簡単です。

2
seand

ほとんどのUtilクラスは次の理由で不良です。

  1. メソッドの範囲を広げます。これらは、そうでなければプライベートになるコードを公開します。 utilメソッドが別々のクラスの複数の呼び出し元で必要であり、安定している(つまり、更新する必要がない)場合、プライベートヘルパーメソッドを呼び出し元のクラスにコピーして貼り付ける方が良いと思います。 APIとして公開すると、jarコンポーネントへのパブリックエントリポイントが何であるかを理解しにくくなります(メソッドごとに1つの親を持つ階層と呼ばれるツリー構造を維持します。これにより、複数の親メソッドから呼び出されるメソッドがあります)。
  2. それらはデッドコードになります。 Utilメソッドは、アプリが進化するにつれて使用されなくなり、未使用のコードがコードベースを汚染することになります。プライベートのままである場合、コンパイラはメソッドが使用されていないことを通知し、それを削除することができます(最良のコードはコードなしです)。そのようなメソッドを非プライベートにすると、コンピューターは無力になり、未使用のコードを削除できなくなります。コンピュータが知っているすべての異なるjarファイルから呼び出すことができます。

静的ライブラリと動的ライブラリにはいくつかの類似点があります。

1

Java 8を使用すると、インターフェースで静的メソッドを使用できます...問題が解決しました。

1
Marc T

ユーティリティクラスは常に悪とは限りません。ただし、これらには幅広い機能に共通のメソッドのみを含める必要があります。限られた数のクラス間でしか使用できないメソッドがある場合は、抽象クラスを共通の親として作成し、その中にメソッドを配置することを検討してください。

0
Sid J