web-dev-qa-db-ja.com

Javaで文字列を使用しないでください。

私は ブログエントリ Javaでの文字列の使用を推奨しないため、代わりにシンラッパークラスを使用する必要があることを示唆しています。これは以前のバージョンです。例の後、上記のエントリは問題を説明するために提供します:

public void bookTicket(
  String name,
  String firstName,
  String film,
  int count,
  String cinema);

public void bookTicket(
  Name name,
  FirstName firstName,
  Film film,
  Count count,
  Cinema cinema);

私がプログラミングブログを読んだ経験から、90%はナンセンスであるという結論に達しましたが、これが有効なポイントかどうか疑問に思いました。どういうわけか私には正しくないと思いますが、プログラミングのスタイルで何が間違っているのか正確に特定できませんでした。

73
DPM

カプセル化は、プログラムをchangeから保護するためにあります。名前の表現は変わりますか?そうでなければ、あなたはあなたの時間を無駄にしており、YAGNIが適用されます。

編集:私はブログ投稿を読みました、そして彼は根本的に良い考えを持っています。問題は、彼がスケールしすぎていることです。おそらく"!"£$%^&*())ADAFVFは有効なorderIdではないので、_String orderId_ isのようなものは本当に悪いです。つまり、Stringは、有効なorderIdsよりもはるかに多くの可能な値を表します。ただし、nameのようなものについては、有効な名前であるかそうでないかを予測できず、Stringは有効なnameです。

最初の例では、(正しく)可能な入力を有効な入力のみに減らしています。 2番目の例では、有効な入力の絞り込みを達成していません。

再度編集:無効な入力の場合を考慮してください。名前として「Gareth Gobulcoque」と書いても、ばかげているように見えるかもしれませんが、世界の終わりではありません。無効なOrderIDを入力すると、機能しない可能性があります。

88
DeadMG

それはただおかしいです:)

46
Makach

私は主に著者に同意します。オーダーIDの検証のように、フィールドに固有のany動作がある場合、そのタイプを表すクラスを作成します。彼の2番目のポイントはさらに重要です。住所などの概念を表すフィールドのセットがある場合は、その概念のクラスを作成します。 Javaでプログラミングしている場合、静的型付けには高額の費用がかかります。できる限りの価値を手に入れることもできます。

23
kevin cline

それをしないでください。それはものを過度に複雑にし、あなたはそれを必要としないでしょう

...は2年前にここで書いたはずの答えです。でも、今はよくわかりません。実際、ここ数か月の間に私は古いコードをこの形式に移行し始めました。何もすることがないからではなく、新しい機能の実装や既存の機能の変更に本当に必要だったからです。ここにいる他の人がそのコードを見ている自動嫌悪を理解していますが、これは真剣に考えるに値するものだと思います。


利点

利点の中で最も重要なのは、コードを変更および拡張する機能です。使用する場合

_class Point {
    int x,y;
    // other point operations
}
_

残念ながら、いくつかの整数を渡すだけではなく、残念ながら、多くのインターフェイスがそうしているのですが、後で別の次元を追加する方がはるかに簡単になります。または、タイプをdoubleに変更します。 _List<Author> authors_の代わりに_List<Person> authors_または_List<String> authors_を使用すると、作成者が表すものにより多くの情報を後で追加することがより簡単になります。このようにそれを書き留めると、明白なことを言っているように感じますが、実際には自分自身でこの方法で文字列を何度も使用していることに罪を犯しています。特に、最初は明白ではなかった場合は、文字列。

私は現在、コード全体で絡み合っている文字列リストをリファクタリングしようとしています。そこではより多くの情報が必要であり、痛みを感じています:\

それを超えて、私はブログの著者に同意しますより多くのセマンティック情報を運ぶ、それは読者が理解しやすくすることです。多くの場合、パラメーターには意味のある名前が付けられ、専用のドキュメンテーションの行を取得しますが、フィールドやローカルの場合はそうではありません。

最終的なメリットはタイプセーフですが、明らかな理由がありますが、私の目では、これはささいなことです。

欠点

書き込みに時間がかかります。小さなクラスを書くことは速くて簡単ですが、特にこれらのクラスをたくさん必要とする場合は、簡単ではありません。新しいラッパークラスを作成するために3分ごとに停止することに気付いた場合、それも集中力を損なう可能性があります。ただし、このような状態は通常、コードを書く最初の段階でのみ発生すると考えたいと思います。私は通常、どのエンティティが関与する必要があるかについてかなり良いアイデアをすばやく得ることができます。

多くの冗長なセッター(または構造)とゲッターが含まれる場合があります。ブログの作者は、new Point(x(10), y(10))ではなくnew Point(10, 10)の本当に醜い例を示しています。また、代わりにMath.max(p.x.get(), p.y.get())のようなものを使用する場合があることを付け加えておきます。 Math.max(p.x, p.y)。そして、長いコードはしばしば読みにくくなると考えられています。しかし、正直なところ、私はlotのコードがオブジェクトを移動し、selectメソッドのみがそれを作成しているように感じます。詳細(とにかくOOPyではありません)。

議論の余地がある

これがreadabilityのコードに役立つかどうかは議論の余地があります。はい、セマンティック情報は増えますが、コードは長くなります。はい、各ローカルの役割を理解する方が簡単ですが、ドキュメントを読んでみないと、ローカルで何ができるかを理解するのが難しくなります。


他のほとんどのプログラミングスクールと同じように、これを極端にするのは不健康だと思います。私は、x座標とy座標をそれぞれ異なるタイプに分離することはありません。 Countで十分な場合、intは必要ないと思います。 Cでの_unsigned int_の使用法は嫌いです-理論的には十分ですが、十分な情報が得られず、魔法の-1をサポートするように後でコードを拡張することは禁止されています。時には、単純さが必要な場合もあります。

ブログ投稿はちょっと極端だと思います。しかし全体として、私は苦痛な経験から、その背後にある基本的な考えは適切なものから作られていることを学びました。

過剰に設計されたコードに対する深い嫌悪感があります。私は本当にそうします。 しかし、正しく使用されている、私はこれが過度に設計されているとは思わない。

16
Oak

それは一種のやり過ぎですが、私が目にしたもののほとんどは、代わりにエンジニアリング不足であると私はしばしば思います。

これは単なる「安全性」ではありません。Javaについての素晴らしい点の1つは、特定のライブラリメソッド呼び出しが必要とするもの/期待するものだけを覚えて/構成するのに役立つことです。

最悪(はるかに)Java私が使用したライブラリは、Smalltalkが非常に好きで、Smalltalkのように機能するようにGUIライブラリをモデル化した問題です-問題すべてのメソッドが同じ基本オブジェクトを取ったが、基本オブジェクトがキャストできるすべてを実際に使用することはできなかったため、メソッドに何を渡すかを推測し、実行時まで失敗したかどうかを知らなかった私がCで作業していたときは、毎回処理する必要があります。

別の問題-オブジェクトなしで文字列、int、コレクション、配列を渡す場合、意味のないデータのボールしかありません。これは、「一部のアプリ」が使用するライブラリの観点から考えると自然なことですが、アプリ全体を設計するときは、データが定義されている場所ですべてのデータに意味(コード)を割り当てて考えるだけの方がはるかに役立ちます。これらの高レベルのオブジェクトがどのように相互作用するかの条件。オブジェクトではなくプリミティブを渡す場合は、定義により、データが定義されている場所とは異なる場所でデータを変更しています(これが、私がセッターとゲッターが本当に好きでない理由でもあります-同じ概念、あなたは操作していますあなたのものではないデータについて)。

最後に、すべてに個別のオブジェクトを定義すると、常にすべてを検証するのに最適な場所になります。たとえば、郵便番号のオブジェクトを作成し、後で郵便番号に常に4桁の拡張子が含まれていることを確認する必要がある場合は、それを置くのに最適な場所。

それは実際には悪い考えではありません。それについて考えると、それがまったく過剰に設計されていたとは言えないかもしれませんが、ほとんどすべての方法で作業するのが簡単です-唯一の例外は小さなクラスの急増ですがJavaクラスは非常に軽量で簡単に記述できるので、コストもかかりません(生成することもできます)。

Javaプロジェクトが実際に定義されているクラスが多すぎて(プログラミングが難しくなったため))、よく書かれているプロジェクトに本当に興味があります。クラスが多すぎます。

5
Bill K

この概念を別の出発点から検討する必要があると思います。データベースデザイナーの観点から見てみましょう。最初の例で渡される型は、パラメーターを独自の方法で定義するものではなく、便利な方法です。

_public void bookTicket(
  String name,
  String firstName,
  String film,
  int count,
  String cinema);
_

チケットを予約している実際の常連客を指定するには2つのパラメーターが必要です。同じ名前の2つの異なる映画(リメイクなど)がある場合と、異なる名前の同じ映画(翻訳など)がある場合があります。映画館の特定のチェーンは異なる支社を持っている可能性があるので、どのように文字列で一貫した方法でそれに対処しますか(たとえば、$chain ($city)または_$chain in $city_または何かを使用していますか?それ以外の場合、これが一貫して使用されていることを確認する方法を教えてください。最悪の場合、実際には2つのパラメーターを使用して顧客を指定します。名と姓の両方が指定されているという事実は、有効な顧客を保証するものではありません(また、 2つの_John Doe_ s)。

これに対する答えは型を宣言することですが、上で示したように、これらが薄いラッパーになることはめったにありません。ほとんどの場合、それらはデータストレージとして機能するか、何らかのデータベースと結合されます。したがって、Cinemaオブジェクトには、名前、場所などが含まれている可能性が高く、そのようなあいまいさを取り除くことができます。それらが薄いラッパーである場合、偶然です。

つまり、ブログの投稿で「正しい型を渡すようにしてください」と言っているだけで、特に基本的なデータ型を選択するために過度に制約された選択を行っただけです(これは間違ったメッセージです)。

提案された代替案はより優れています:

_public void bookTicket(
  Name name,
  FirstName firstName,
  Film film,
  Count count,
  Cinema cinema);
_

一方で、ブログの投稿はすべてをラップすることで行き過ぎだと思います。 Countは一般的すぎるので、それを使ってリンゴやオレンジを数え、それらを追加しても、型システムで無意味な操作を実行できる状況が手に残っています。もちろん、ブログと同じロジックを適用して、CountOfOrangesなどの型を定義することもできますが、これもばかげています。

それが価値があるもののために、私は実際に次のようなものを書きます

_public Ticket bookTicket(
  Person patron,
  Film film,
  int numberOfTickets,
  Cinema cinema);
_

要するに、無意味な変数を渡してはいけません。実際のオブジェクトを決定しない値を持つオブジェクトを実際に指定するのは、クエリを実行するとき(例:public Collection<Film> findFilmsWithTitle(String title))または証明をまとめるときだけです。概念。タイプシステムをクリーンな状態に保ち、一般的すぎるタイプ(たとえば、Stringで表される映画)や過度に制限的/特定的/不自然なタイプ(たとえば、Countではなくint)を使用しないでください。可能な限り実行可能な場合は常に、オブジェクトを一意かつ明確に定義する型を使用してください。

編集:さらに短い要約。小規模なアプリケーション(概念実証など)の場合:なぜ複雑な設計に悩むのですか? Stringまたはintを使用して、それを実行してください。

大規模なアプリケーションの場合:基本的なデータ型の単一のフィールドで構成されるクラスがたくさんある可能性は本当にありますか?そのようなクラスがほとんどない場合は、「通常の」オブジェクトだけがあり、特別なことは行われません。

文字列をカプセル化するという考えは、...単なる不完全なデザインです。小さなアプリケーションでは過度に複雑で、大きなアプリケーションでは十分ではありません。

3
Egon

私にとってこれは、C#でリージョンを使用するのと同じです。一般に、コードを読みやすくするためにこれが必要であると感じる場合は、時間を費やす必要があるより大きな問題があります。

2
Tom Squires

強く型付けされたtypedefのような機能を持つ言語では、これは本当に良いアイデアだと思います。

Javaではこれがないので、これらのもののためにまったく新しいクラスを作成することは、コストが利益を上回ることを意味します。変数/パラメータに注意することによって、利益の80%を得ることができます。ネーミング。

2
jk.

IF String(End Integer、... Stringについてのみ話す)は最終的なものではなかったので、これらのクラスは意味のある(制限された)Stringであり、処理方法を知っている独立したオブジェクトに送信できます基本タイプ(やり取りせずに)。

そして、例えばあるとそれの「良さ」が増加します。すべての名前に対する制限。

しかし、(ライブラリではなく)アプリを作成するときは、常にそれをリファクタリングすることができます。だから私はそれなしでスタートする準備をしています。

0
user470365

例を挙げましょう:現在開発されているシステムには、(外部システムの使用により)複数の種類の識別子で識別できる多数の異なるエンティティがあり、時には同じ種類のエンティティでさえあります。すべての識別子は文字列です。つまり、パラメーターとして渡されるIDの種類を混同しても、コンパイル時エラーは表示されませんが、プログラムは実行時に異常終了します。これはかなり頻繁に発生します。したがって、この原則の主な目的は変更から保護することではなく(変更にも役立ちます)、バグから身を守ることです。とにかく、誰かがAPIを設計する場合、それはドメインの概念を反映する必要があるので、ドメイン固有のクラスを定義することは概念的に有用です-すべては開発者の念頭に秩序があるかどうかに依存し、これは非常に可能性があります型システムによって促進されます!

0
thSoft