Javaで書かれたAPIで内部クラスをカプセル化する方法は?


9

ライブラリを書かなければならない。当然、非常に小さなAPI(必要に応じてできるだけ広い)のみを使用する必要があります。ライブラリの内部はやや複雑です。したがって、構造化が必要です。

構造化について、私は現在2つの方法を考えています。

1.パッケージを使用します。

長所:ライブラリはきちんと構成できます。その場所のすべて。

短所:パッケージの境界線を介したクラスの使用にはパブリッククラスが必要であり、したがってライブラリ全体のAPIを拡張します。

2.すべて1つのパッケージで静的内部クラスを使用します。

長所:必要なパブリッククラス(クラス、メソッドなど)はごくわずかです。

短所:クラスは、それらを構造化するためにのみ非表示になります。これは、非常に多くの静的内部クラスが使用される非常に数少ないユースケースの1つです。開発者はそれに慣れておらず、見落とす可能性があります。


よく構造化されたライブラリで小さなAPIを実現するより良い方法はありますか?

編集:言及するのを忘れていました:Androidライブラリ用です。したがって、java9はありません。


内部クラスを静的にする必要があるのはなぜですか?
David Arno、2016

内部クラスはコード単位を大きくしませんか?つまり、複数の内部クラスを持つクラスが非常に長くなる可能性があります。
TulainsCórdova16年

2
@TulainsCórdova、良い点、私は「inner」という用語を「internal」と読みましたが、これはJavaが「package-private」と呼んでいると思います。libを作成する通常の方法は、いくつかのパブリッククラスを含む1つのパッケージを確実に作成し、それ以外はすべてinternal / package-privateにすることです。
David Arno

こんにちは@frmarkus。質問のタイトルをより具体的なものに書き直し、「何を求めているのか不明確」な近い票を避けました。実際の質問を誤って表していると思われる場合は、自由に再編集してください。
Andres F.

1
@TulainsCórdova:はい、コード単位は大きくなります(ファイルごとに3k行​​のコード)。これは、この構造化方法のもう1つの重要な問題です。
Markus Frauenfelder

回答:


1

私はあなたが何をしているのかを理解しています。クラスをパッケージとして、パッケージをモジュールとして使用しているため、パッケージ内で自分自身を分離しながら、クラスを使用してパッケージ内で整理できます。

それはとても賢いです。賢いことに注意してください。

これにより、同じソースファイル内の複数のクラスを妨害するように強制され(好まれるかもしれません)、パスには余分な大文字の単語が含まれます。

また、リフレクションを使用して外部から侵入する場合を除いて、パッケージ内にテストコードを作成する必要があります。

それ以外の場合、これは機能します。変に見えるだけです。

人々はHashtableのEntrySetのように使用されている内部クラスにより慣れています。プライベートなので作成できませんが、パブリックインターフェースを実装しているので、インターフェースを介して話しかけるだけで、何かを手に入れられます。

しかし、インターフェースを介しても私に話してほしくないクラスを説明している。だから私にはインターフェースはありません。これは、私が見るものも混乱するものもないことを意味します(ソースを提供しない限り)。

私が予測する最大の問題は、APIを維持するこの混乱している初心者です。あなたはそれらにドキュメンテーションとコメントを投げることができますが、彼らがどちらも読んだり信頼したりしないときは特大になりません。

言語の不足を埋め合わせるさらに別のパターンを作成しました。Javaには、パッケージのグループへのアクセスを許可するアクセス修飾子はありません。「モジュール」アクセス修飾子が提案されたと聞きましたが、その兆候は見られません。

デフォルトのアクセス修飾子(修飾子なし)は、継承を通じてこっそり侵入しても構わない場合を除いて、ここで使用する可能性が高く、その場合は保護されます。

Modifier        Class     Package   Subclass  World
public          Y         Y         Y         Y
protected       Y         Y         Y         N
no modifier     Y         Y         N         N
private         Y         N         N         N 

あなたが本当に望んでいるのはモジュールへのアクセスです。そうすれば、テストを1つのパッケージにまとめ、コードを別のパッケージにまとめることができます。残念ながら、Javaにはありません。

ほとんどの人は1を実行してAPIを拡張します。インターフェイスを適切に使用することで、実装か​​らのプレッシャーがなくなります。

必要なものを1にハッキングすることは、さらに醜いことです。コールスタックをのぞいて、呼び出し元が気に入らないパッケージからのものである場合は常に例外をスローします。ええ。


2

必ず、コードをパッケージに分けてください。保守性の向上に大きく貢献します。

エンドユーザーがアクセスしてはいけないものにアクセスできないようにするには、APIをインターフェースと実装に分離する必要があります。

Javaインターフェースの観点からAPI全体を定義し、実装オブジェクトを生成するためにいくつかのファクトリー・クラスを提供することにより、文字通りそれを行うことができます。これはJDBCが行うことです。

または、internalパッケージを作成し、それらのパッケージを実装依存であり、警告や下位互換性なしに変更される可能性があることを文書化することにより、慣例としてそれを行うことができます。


1
残念ながら、これは完全なノーゴーです。これは多くの公開クラスに任されています。彼らは(工場または「内部」である)ヒントを持っているかもしれません。しかし、私はそれらに(すべてのパブリッククラスに)追加のツールを適用する必要があります。これは単に良いことではありません。
Markus Frauenfelder

@frmarkus-(1)アクセス制御に期待しすぎている、または(2)パッケージ構造を再考して、あるパッケージのクラスが別のパッケージのクラスに依存する必要がないようにする必要があると思いますパッケージ(静的なネストされたクラスとしてすべてを保持できる場合、これは難しくありません)。
kdgregory 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.