11

私は Java RegexLibraryを見直してきましたがPattern、私が何年もの間当たり前だと思っていた public コンストラクターがクラスにないという事実に驚きました。

静的メソッドがコンストラクターを優先して使用されていると思われる理由の 1 つcompileは、パターン文字列が同じであれば、静的メソッドが以前に作成された (およびキャッシュされた) オブジェクトを返す可能性があるのに対し、コンストラクターは常に新しいオブジェクトを返す可能性があるためです。

ただし、以下に示すように、そうではありません。

public class PatternCompiler {
    public static void main(String[] args) {
        Pattern first = Pattern.compile(".");
        Pattern second = Pattern.compile(".");
        if (first == second) {
            System.out.println("The same object has been reused!");
        } else {
            System.out.println("Why not just use constructor?");
        }
    }
}

コンストラクターよりも静的メソッドを使用することの背後にある他の強力な根拠はありますか?

編集:ここで関連する質問が見つかりました。そこにある答えのどれも私を納得させませんでした。すべての回答を読んで、オブジェクトの作成に関して静的メソッドにはパブリックコンストラクターよりもかなりの利点があると感じていますが、その逆ではありません。本当?もしそうなら、クラスごとにそのような静的メソッドを作成し、それがより読みやすく柔軟であると安全に想定します。

4

6 に答える 6

15

一般に、次の 3 つの理由のいずれかにより、クラスにはパブリック コンストラクターがありません。

  • クラスはユーティリティ クラスであり、インスタンス化する必要はありません (たとえば、java.lang.Math)。
  • インスタンス化は失敗する可能性があり、コンストラクターは を返すことができませんnull
  • 静的メソッドは、インスタンス化中に何が起こるかの背後にある意味を明確にします。

のクラスでPatternは、3 番目のケースが適用されます。静的compileメソッドは、わかりやすくするためにのみ使用されます。を介してパターンを構築するnew Pattern(..)ことは、新しいPattern. このプロセスを説明するために、静的メソッドは という名前が付けられcompileています。これは、正規表現が基本的にコンパイルされてパターンが作成されるためです。

要するに、Pattern静的メソッドを介してのみ構築可能にするためのプログラム上の目的はありません。

于 2012-12-07T07:50:29.270 に答える
6

これは単なる設計上の決定です。この場合、「本当の」利点はありません。ただし、この設計により、API を変更せずに最適化 (キャッシュなど) が可能になります。http://gbracha.blogspot.nl/2007/06/constructors-considered-harmful.htmlを参照してください。

于 2012-12-07T07:46:53.807 に答える
5

ファクトリ メソッドにはいくつかの利点があり、そのうちのいくつかは他の回答で既に指定されています。コンストラクターの代わりにファクトリ メソッドを検討するようにというアドバイスは、Joshua Bloch の著書「Effective Java」(すべての Java プログラマーにとって必読) の最初の章にもあります。


利点の 1 つは、パラメーター シグネチャが同じで名前が異なる複数のファクトリ メソッドを使用できることです。これは、コンストラクターでは実現できません。

たとえば、Patternいくつかの入力フォーマットから を作成したい場合がありますが、それらはすべてStrings だけです:

class Pattern {
  compile(String regexp) { ... }
  compileFromJson(String json) { ... }
  compileFromXML(String xml) { ... }
}

クラスを作成するときにこれを行わなくても、ファクトリ メソッドを使用すると、奇妙なことを引き起こすことなく、後でそのようなメソッドを追加できます。

たとえば、新しいコンストラクターが後で必要になり、オーバーロードを可能にするために特別な意味のない 2 番目のパラメーターを 2 番目のコンストラクターに追加する必要があるクラスを見てきました。明らかに、これは非常に醜いです:

class Ugly {
  Ugly(String str) { ... }

  /* This constructor interpretes str in some other way.
   * The second parameter is ignored completely. */
  Ugly(String str, boolean ignored) { ... }
}

残念ながら、そのようなクラスの名前は思い出せませんが、Java API にもあったと思います。


これまでに言及されていないもう 1 つの利点は、ファクトリ メソッドをパッケージ プライベート コンストラクターと組み合わせて使用​​すると、他のユーザーのサブクラス化を禁止しながら、サブクラスを自分で使用できることです。の場合、、、およびPatternのようなプライベート サブクラスが必要な場合がありますが、不変性を保証するためにサブクラス化を禁止します。CompiledPatternLazilyCompiledPatternInterpretedPattern

パブリック コンストラクターを使用すると、すべてのサブクラス化を禁止することも、まったく禁止することもできます。

于 2012-12-07T07:53:49.047 に答える
2

本当に深く掘り下げたい場合は、JSR 51 のアーカイブに飛び込んでください。

正規表現は JSR 51 の一部として導入されました。これは、アーカイブで設計上の決定を見つけることができる場所です: http://jcp.org/en/jsr/detail?id=51

于 2012-12-07T07:51:03.093 に答える