8

これがシナリオです。公に認可されたオープン ソース API の作成者として、私のグループは Java ベースの Web ユーザー インターフェイス フレームワークを作成しました (それ以外に何が新しいのでしょうか?)。Java で物事を適切に整理するために、命名規則 org.mygroup.myframework.x を持つパッケージを使用しました。x は、コンポーネント、バリデーター、コンバーター、ユーティリティなどのようなものです (繰り返しますが、他には何がありますか?新着?)。

ここで、クラス org.mygroup.myframework.foo.Bar のどこかにvoid doStuff()、フレームワークに固有のロジックを実行する必要があるメソッドがあり、フレームワークの他のいくつかの場所 (org. mygroup.myframework.far.Boo. Boo が Bar のサブクラスでもまったく同じパッケージでもないことを考えると、メソッド doStuff() は、Boo から呼び出せるように public として宣言する必要があります。

ただし、私のフレームワークは、他の開発者がクライアント用によりシンプルで洗練された RIA を作成できるようにするためのツールとして存在します。しかし、com.yourcompany.yourapplication.YourComponent が doStuff() を呼び出すと、予期しない望ましくない結果が生じる可能性があります。私は、これが決して起こらないことを望みます。 Bar には、真にパブリックな他のメソッドが含まれていることに注意してください。

象牙の塔の世界では、Java 言語を書き直して、トークン化されたアナログをデフォルト アクセスに挿入します。これにより、選択したパッケージ構造内の任意のクラスが私のメソッドにアクセスできるようになります。おそらく次のようになります。

[org.mygroup.myframework.*] void doStuff() { .... }

ここで、ワイルドカードは、パッケージが org.mygroup.myframework で始まるすべてのクラスを呼び出すことができますが、他の誰も呼び出すことができないことを意味します。

この世界が存在しないことを考えると、他にどのような良い選択肢があるでしょうか?


これは実際のシナリオに基づいていることに注意してください。有罪を保護するために名前が変更されました。実際のフレームワークが存在し、Javadoc 全体に散りばめられたパブリック メソッドには、「このメソッドは MYFRAMEWORK の内部であり、パブリック API の一部ではありません。呼び出さないでください!!!!!!」とコメントされています。少し調査したところ、これらのメソッドはフレームワーク内の別の場所から呼び出されていることがわかりました。

実は、私は問題のフレームワークを使用している開発者です。私たちのアプリケーションはデプロイされ、成功していますが、私のチームは非常に多くの課題を経験したため、上司にこのフレームワークを二度と使用しないよう説得したいと考えています。私たちはこれを、フレームワークの開発者が下した不適切な設計上の決定をよく考え抜いた形で提示したいと考えています。単なる暴言としてではありません。この問題は、(いくつかの) ポイントの 1 つですが、どうすれば別の方法で解決できたのかはわかりません。私の職場ではすでに活発な議論が行われているので、他の人はどう思うだろうかと思いました。


更新: これまでのところ 2 人の回答者に不快感を与えることはありませんが、的を外したか、うまく表現できなかったと思います。いずれにせよ、私が物事を照らそうとすることを許可してください. できるだけ簡単に言えば、フレームワークの開発者は次のことをどのようにリファクタリングするべきでしたか。これは非常に大まかな例であることに注意してください。

package org.mygroup.myframework.foo;
public class Bar {
     /** Adds a Bar component to application UI */
     public boolean addComponentHTML() {
         // Code that adds the HTML for a Bar component to a UI screen
         // returns true if successful
         // I need users of my framework to be able to call this method, so
         // they can actually add a Bar component to their application's UI
     }

     /** Not really public, do not call */
     public void doStuff() {
         // Code that performs internal logic to my framework
         // If other users call it, Really Bad Things could happen!
         // But I need it to be public so org.mygroup.myframework.far.Boo can call
     }
}

別の更新: C# に「内部」アクセス修飾子があることを知りました。したがって、この質問を表現するより良い方法は、「Java で内部アクセスをシミュレート/エミュレートする方法は?」ということだったかもしれません。とはいえ、私は新しい答えを探しているわけではありません。私たちの上司は最終的に上記の懸念に同意しました

4

4 に答える 4

0

インターフェイスと動的プロキシは、公開したいメソッドのみを公開するために使用されることがあります。

ただし、メソッドが頻繁に呼び出されると、かなりのパフォーマンス コストが発生します。

注釈を使用する@Deprecatedことも選択肢の 1 つかもしれませんが、外部ユーザーが「フレームワーク プライベート」メソッドを呼び出すのを止めることはできませんが、警告を受けていなかったとは言えません。

一般に、ユーザーが何かを使用してはならないことを明確に示している限り、ユーザーが故意に自分の足を撃ちすぎることを心配する必要はないと思います。

于 2012-05-31T16:11:27.233 に答える
0

この不足している「フレームワーク レベル アクセス修飾子」を提供するために私が考えることができる唯一のアイデアは、CDI とより良い設計です。さまざまな (ただし少数の) 状況で非常に異なるクラスやパッケージのメソッドを使用する必要がある場合、それらのメソッドを「プライベート」にしてアクセスできないようにするために、それらのクラスを再設計する方法が確かにあります。

于 2012-05-18T14:01:35.757 に答える
0

そのような種類のアクセス レベルに対する Java 言語のサポートはありません (名前空間を使用した「内部」のようなものが必要です)。パッケージ レベル (または既知の継承 public-protected-private モデル) へのアクセスのみを制限できます。

私の経験から、Eclipse の規則を使用できます。このパッケージのすべてのクラス階層 (サブパッケージを含む) が非 API コードと見なされ、ユーザーに対する保証なしでいつでも変更できる「内部」と呼ばれるパッケージを作成します。その非 API コードでは、好きなときにパブリック メソッドを使用します。これは単なる規則であり、JVM や Java コンパイラによって強制されるものではないため、ユーザーがコードを使用するのを防ぐことはできませんが、少なくとも、これらのクラスがサード パーティによって使用されることを意図していないことをユーザーに知らせてください。

ところで、Eclipse プラットフォームのソース コードには、プラグインごとにカスタム クラス ローダーを実装することで、他のプラグインの内部コードを使用しないよう強制する複雑なプラグイン モデルがあり、これらのプラグインで「内部」であるべきクラスのロードを防止します。

于 2012-05-18T14:07:45.970 に答える
0

ドキュメントの問題に言及すると、答えに最も近づきます。本当の問題は、内部メソッドを「保護」できないことではありません。むしろ、内部メソッドがドキュメントを汚染し、クライアント モジュールが誤って内部メソッドを呼び出す可能性があるというリスクをもたらします。

もちろん、きめの細かいパーミッションを持っていたとしても、クライアント モジュールが内部メソッドを呼び出すのを防ぐことはできません。とにかく、jvm はプライベート メソッドへのリフレクション ベースの呼び出しから保護しません。

私が使用するアプローチは、問題のあるクラスごとにインターフェイスを定義し、クラスにそれを実装させることです。インターフェイスは、クライアント モジュールの観点からのみドキュメント化できますが、実装クラスは、必要な内部ドキュメントを提供できます。配布バンドルに javadoc の実装を含めたくない場合でも、含める必要はありませんが、どちらにしても境界は明確に区別されます。

実行時にドキュメント インターフェイスごとに 1 つの実装のみが読み込まれることを保証する限り、最新の jvm は、それを使用してもパフォーマンスが低下しないことを保証します。また、テスト中にハーネス/スタブのバージョンをロードして、追加のボーナスを得ることができます。

于 2012-06-12T01:03:22.103 に答える