web-dev-qa-db-ja.com

ライブラリをサブパッケージに分解しながらJavaライブラリの公開されたインターフェースサーフェスを最小化する方法は?

Androidアプリ用に1つまたは2つのライブラリを作成しています。ライブラリの公開されたインターフェイスを最小限にして、すべてのクラスを 'public'にすることを避けて、あらゆる場所で抽象化が漏れないようにしたいと思います。私は Mavenのパッケージ構造 もフォローしています。

C#から来て、私はinternalアクセス修飾子を使用して私がやりたいことを達成しました。慣れていない場合、internalはアセンブリ内のすべてのアクセスを許可しますが、アセンブリの外部は許可しません。したがって、いくつかのパブリックインターフェイスは本当にパブリックです。私の意見では、最も近い類推はJavaのpackage-privateですが、ライブラリをサブパッケージに編成すると、それはうまくいきません。

たとえば、ルートにService1クラスがあり、ルートの下のサブパッケージに別のクラスService2があるとします。 Service1Service2のインターフェースを参照できるようにしたいのですが、Service2publicを作成しないでください。これにより、パッケージの外部にService2のインターフェースが公開されるため、意図したとおりではありません。

これはそれほど複雑ではないと思いますが、兄弟/親パッケージがpublicにせずにサブパッケージクラスにアクセスできるようにする方法については、少し混乱しています。私が本当に考えることができた唯一の解決策は、1)package-privateを使用して、公開してはいけないが非常に厄介なものをすべて隠すことができる同じパッケージレベルにすべてを置くか、または2)吸い込むことです。インターフェースを公開して公開します。これは明らかに私の感性を害します。

これは通常どのように行われますか?すべてのクラスは同じパッケージ内にありますが、サブディレクトリごとに編成されている可能性がありますか?自分が本当に好きなアプローチをまだ思いついていない。

6
JosephRT

Javaでは、目的のAPIサーフェスでパッケージ構造を定義する必要があります。 API設計に直接関係しない方法でファイルを「整理」するためだけにサブパッケージを作成するという誘惑を避けてください。そうする必要があると認識されている必要性は、不十分なAPI設計を示唆しているかもしれません。

そのことを念頭に置いて、サブパッケージを使用して内部APIを作成することもできます。たとえば、クラスのグループでは、特定のメンバーがグループ内の他のクラスにアクセスできるようにしたいが、それらのメンバーをライブラリの残りの部分に公開しない場合があります。その場合は、それらをサブパッケージに入れ、パッケージプライベートアクセスを利用します。サブパッケージの公開されたAPIが、個別の製品として設計、文書化、およびサポートしたいものであるかどうかを慎重に検討する必要があります。そうすることはあなたの製品をより価値のあるものにしますが、もちろんあなたにはいくらかのコストがかかります。内部APIをサポートしない場合、またはまだ不明な場合、通常の解決策は、そのAPIをcom.myproduct.internalのように内部として識別する名前、または必要に応じて公開されているが、公式には標準の一部ではないcom.Sunクラスのように、完全に異なるパッケージ階層Java API。

5
StackOverthrow

Androidがサポートしているかどうかはわかりません。ただし、Java 9のアップデートの主な機能はこの問題に関するものです。

Java 9(Project Jigsawとして知られている))のモジュール機能を使用すると、メタデータファイルを.jarに追加して、(特に)公開されているパッケージを一覧表示できます。パッケージはモジュールの内部にあります。つまり、内部モジュール内のパブリッククラスは、.Netアセンブリの内部クラスに相当します。

5
Sebastian Redl

標準的なJava=方法は、追加のパッケージを作成しないか、内部でパッケージ呼び出しを使用しないことです。Androidで使用できる別のオプションを指摘したいと思います。

AndroidにはサポートアノテーションRestrictToがあります。適切なスコープ外で注釈付きコードを使用すると、誰でもlint警告が表示されます。

https://developer.Android.com/reference/Android/support/annotation/RestrictTo

これにより、クラス、メソッド、またはフィールドに、ライブラリ自体に制限されているものとして注釈を付けることができます。

@RestrictTo(RestrictTo.Scope.LIBRARY)

スコープには他のオプションもあります。これは、Googleがサポートライブラリで採用してきたパターンです。

2
Michael Krussel

各サブディレクトリはJavaの新しいパッケージであるため、「しかし、サブディレクトリごとに編成されている可能性があります」という意味はありません。

通常行われることは、パッケージによるパブリックインターフェイスの内容を文書化し、実装クラスを変更可能であることを文書化することです。これらは、自己の責任において直接使用してください。

また、これを効果的に使用していることを確認した方法の1つは、ライブラリを2つのjarファイルに分割することです。 1つはパブリックAPIのインターフェースのみを含むファイル、もう1つはその他すべてのファイルを含みます。一般にリリースするバージョンでは、インターフェースについては十分なドキュメントを提供し、実装クラスについてはドキュメントを提供しないでください。

そして、ユーザーにある程度の信頼を置きます。パブリックAPIに固執することを信頼してください。十分に設計されていれば、内部を直接いじる必要はありません。内部をいじると、自分の作業がはるかに壊れやすくなるからです。

1
jwenting