公式から documentation ...
修飾子クラスパッケージサブクラスワールド 公開Y Y Y Y 保護されたY Y Y N 修飾子なしY Y N N プライベートY N N N
問題は、同じパッケージ内のクラスから保護されたメンバーにアクセスする必要があったユースケースを思い出せないことです。
この実装の背後にある理由は何ですか?
編集:明確にするために、同じパッケージ内のサブクラスとクラスの両方が保護フィールドにアクセスする必要がある特定のユースケースを探しています、または方法。
package some.package;
public class A {
protected void protectedMethod(){
// do something
}
}
package another.package;
public class B extends A{
public void someMethod(){
// accessible because B is a subclass of A
protectedMethod();
}
}
package some.package;
public class C {
public void anotherMethod(){
// accessible because C is in the same package as A
protectedMehtod();
}
}
同じパッケージ内のサブクラスとクラスの両方が保護されたフィールドまたはメソッドにアクセスする必要がある特定のユースケースを探しています...
私にとっては、このようなユースケースは特定のものではなく一般的であり、それは私の好みから次のように派生します。
上記から、デフォルトのアクセス修飾子を使用してオブジェクトの設計を開始できます(private
から始めますが、単体テストは複雑になります)。
_public class Example {
public static void main(String [] args) {
new UnitTest().testDoSomething(new Unit1(), new Unit2());
}
static class Unit1 {
void doSomething() {} // default access
}
static class Unit2 {
void doSomething() {} // default access
}
static class UnitTest {
void testDoSomething(Unit1 unit1, Unit2 unit2) {
unit1.doSomething();
unit2.doSomething();
}
}
}
_
上記のスニペットのメモ、_Unit1
_、_Unit2
_およびUnitTest
は nested 内でExample
内にあります。 、私はこれらのクラスを別々のファイルに(そしてUnitTest
さえ 別のディレクトリに )持つでしょう。
次に、必要に応じて、アクセス制御をデフォルトからprotected
に弱めます。
_public class ExampleEvolved {
public static void main(String [] args) {
new UnitTest().testDoSomething(new Unit1(), new Unit2());
}
static class Unit1 {
protected void doSomething() {} // made protected
}
static class Unit2 {
protected void doSomething() {} // made protected
}
static class UnitTest {
// ---> no changes needed although UnitTest doesn't subclass
// ...and, hey, if I'd have to subclass... which one of Unit1, Unit2?
void testDoSomething(Unit1 unit1, Unit2 unit2) {
unit1.doSomething();
unit2.doSomething();
}
}
}
_
ご覧のとおり、オブジェクトへのアクセスがサブクラスではない場合でも、同じパッケージから保護されたメソッドにアクセスできるため、ユニットテストコードをExampleEvolved
に変更せずに維持できます。
必要な変更が少ない=>より安全な変更。結局のところ、アクセス修飾子のみを変更し、Unit1.doSomething()
およびUnit2.doSomething()
が実行するメソッドを変更しなかったので、単体テストコードが変更なしで実行し続けることは当然のことです。
私見、これはJavaの設計上の悪い決定でした。
推測するだけですが、私はアクセスレベルを厳格に発展させたいと考えていました。プライベート-「パッケージ」-保護-パブリック。彼らは階層を持っていたくありませんでした。サブクラスではなくパッケージで利用できるフィールド、サブクラスでは利用できるがパッケージでは利用できないフィールド、およびその両方の階層があります。
それでも、私の控えめな意見では、彼らは反対の方向に進んでいるはずでした:protectedはクラスとサブクラスのみに表示され、そのパッケージはクラス、サブクラス、およびパッケージに表示されます。
私はしばしば、サブクラスからアクセス可能である必要があるが、パッケージの他の部分からはアクセス可能でなければならないクラスにデータを持っています。私はその逆が真実である場合を考えるのは難しいです。データを共有する必要があるが、そのデータをバンドルの外部から安全に保つ必要のある相互に関連するクラスのバンドルがあるまれな状況がいくつかありました。だから大丈夫、パッケージなどに入れてください。でも、パッケージでデータを共有したいというケースは一度もありませんが、サブクラスには入れないようにしたいです。さて、私は状況が近づくのを想像できます。このパッケージが、私が何も知らないクラスによって拡張される可能性のあるライブラリの一部である場合、私はクラスのデータをプライベートにするのと同じ理由でそうなります。ただし、クラスとその子だけがデータを使用できるようにするほうが一般的です。
私と子供たちの間には私が秘密にしておくことがたくさんあり、私たちは隣人と共有しません。私と近所の人との間で秘密を守り、子供たちと共有しないことはほとんどありません。 :-)
これには2つの部分があります。
protected
とまったく同じです。すぐに頭に浮かぶ良い例は、パッケージでよく使用されるユーティリティクラスですが、パブリックアクセスは必要ありません(behind-the-scenes-image-loading-from-disk、handle-creation/destructionクラスなど)。 。)すべてを作成する代わりに[Javaの同等のfriend access modifier or idiom
C++
]他のすべてのクラスのすべてが自動的に使用可能になります。
Protected/packageアクセス修飾子の使用例は、C++のfriendアクセス修飾子の使用例と似ています。
Mementoパターン 。を実装する場合が1つの使用例です。
元に戻す操作のチェックポイントとして機能するために、mementoオブジェクトはオブジェクトの内部状態にアクセスして保持する必要があります。
Javaにはないため、同じパッケージでクラスを宣言すると、oneでMementoパターンを実現できます。 "friend"アクセス修飾子。