29

インターフェイスはパブリックでなければならないことを知っています。しかし、私はそれを望んでいません。

実装したメソッドは、それ自体のパッケージからのみアクセスできるようにしたいので、実装したメソッドを保護したいと考えています。

問題は、インターフェイスまたは実装されたメソッドを保護できないことです。

回避策とは何ですか? この問題に関連する設計パターンはありますか?

Javaガイドから、抽象クラスも仕事をしません。

4

12 に答える 12

25

これを読んでください。

「パブリックアクセス指定子は、インターフェイスが任意のパッケージの任意のクラスで使用できることを示します。インターフェイスがパブリックであることを指定しない場合、インターフェイスは、インターフェイスと同じパッケージで定義されたクラスにのみアクセスできます。」

それはあなたが望むものですか?

于 2009-01-08T02:29:13.243 に答える
11

クラスはパッケージ保護を使用しても、インターフェイスを実装できます。

class Foo implements Runnable 
{
    public void run()
    {
    }
}

一部のメソッドを保護/パッケージ化し、他のメソッドを保護しない場合は、クラスに複数の責任があるように思われるため、複数に分割する必要があります。

これと他の応答へのコメントを読んだ後に編集してください:

メソッドの可視性がそのメソッドを呼び出す機能に影響を与えると何らかの理由で考えている場合は、もう一度考えてみてください。極端に行かなければ、誰かがリフレクションを使用してクラスのメソッドを識別し、それらを呼び出すことを防ぐことはできません。ただし、これは問題ではありません。誰かがコードを解読しようとしない限り、ランダムなメソッドを呼び出すことはありません。

代わりに、プライベート/保護されたメソッドをサブクラスのコントラクトを定義するものと考え、インターフェイスを使用して外部とのコントラクトを定義します。

ああ、そして私の例を決定した人には、K&Rブレースを使用する必要があります。それが利用規約で指定されている場合は、確かに。そうでなければ、あなたはあなたの時間ともっと良いことを見つけることができませんか?

于 2009-01-08T02:29:51.743 に答える
8

これに反対したときは、パッケージ アクセス可能な内部クラスまたはネストされたクラスを使用してインターフェイスを実装し、実装されたメソッドをパブリック クラスからプッシュします。

通常、それは、特定のパブリック API を持つクラスがあり、それが仕事を完了するために何か他のものを実装する必要があるためです (他の何かがインターフェース <grin> を装ったコールバックであることが非常に多いため) - これは Comparable のようなものでよく起こります。パブリック API が (強制されたパブリック) インターフェイスの実装で汚染されることは望ましくありません。

お役に立てれば。

また、パッケージによってのみアクセスされるメソッドが本当に必要な場合は、保護されたスコープ指定子は必要なく、デフォルトの (省略された) スコープ指定子が必要です。もちろん、protected を使用すると、サブクラスがメソッドを参照できるようになります。

ところで、インターフェイス メソッドがパブリックであると推論される理由は、同じパッケージ内のクラスによってのみ実装されるインターフェイスを持つことはほとんど例外であるためだと思います。ほとんどの場合、それらは別のパッケージ内の何かによって呼び出されます。つまり、それらはパブリックである必要があります。

于 2009-01-08T03:02:09.527 に答える
4

この質問は、間違ったステートメントに基づいています。

インターフェイスはパブリックでなければならないことを知っています

そうではありませんが、デフォルトのアクセス修飾子を持つインターフェイスを持つことができます。

問題は、インターフェイスまたは実装されたメソッドを保護できないことです

ここにあります:

C:\oreyes\cosas\java\interfaces>type a\*.java
a\Inter.java
package a;

interface Inter {
    public void face();
}

a\Face.java
package a;

class Face implements Inter {
    public void face() {
        System.out.println( "face" );
    }
}


C:\oreyes\cosas\java\interfaces>type b\*.java
b\Test.java

package b;
import a.Inter;
import a.Face;

public class Test {
    public static void main( String [] args ) {
        Inter inter = new Face();
        inter.face();
    }
}

C:\oreyes\cosas\java\interfaces>javac -d . a\*.java b\Test.java
b\Test.java:2: a.Inter is not public in a; cannot be accessed from outside package
import a.Inter;
        ^
b\Test.java:3: a.Face is not public in a; cannot be accessed from outside package
import a.Face;
        ^
b\Test.java:7: cannot find symbol
symbol  : class Inter
location: class b.Test
        Inter inter = new Face();
        ^
b\Test.java:7: cannot find symbol
symbol  : class Face
location: class b.Test
        Inter inter = new Face();
                          ^
4 errors

C:\oreyes\cosas\java\interfaces>

したがって、必要なものを達成するには、パッケージの外部でインターフェイスとクラスを使用しないようにします。

于 2009-01-13T06:31:08.533 に答える
3

抽象クラスを使用してこれを行う方法は次のとおりです。

唯一の不便な点は、それがあなたを「サブクラス」にすることです。

Javaガイドによると、ほとんどの場合、そのアドバイスに従う必要がありますが、この状況では問題ないと思います。

public abstract class Ab { 
    protected abstract void method();
    abstract void otherMethod();
    public static void main( String [] args ) { 
        Ab a = new AbImpl();
        a.method();
        a.otherMethod();
    }
}
class AbImpl extends Ab {
    protected void method(){
        System.out.println( "method invoked from: " + this.getClass().getName() );
    }
    void otherMethod(){ 
        System.out.println("This time \"default\" access from: " + this.getClass().getName()  );
    }
}
于 2009-01-08T02:30:09.933 に答える
1

テストケースでのみ使用されることを意図して保護されたメソッドを構築しようとして、これに出くわしました。DB テーブルに詰め込んだテスト データを削除したかったのです。いずれにせよ、@Karl Giesing投稿に触発されました。残念ながらうまくいきませんでした。保護された内部クラスを使用して機能させる方法を考え出しました。

インターフェース:

package foo;
interface SomeProtectedFoo {
    int doSomeFoo();
}

次に、パブリック クラスで保護されていると定義された内部クラス:

package foo;
public class MyFoo implements SomePublicFoo {
    // public stuff
    protected class ProtectedFoo implements SomeProtectedFoo {
        public int doSomeFoo() { ... }
    }
    protected ProtectedFoo pFoo;
    protected ProtectedFoo gimmeFoo() {
        return new ProtectedFoo();
    }
}

私のテストコードが示すように、同じパッケージ内の他のクラスからのみ保護されたメソッドにアクセスできます。

package foo;
public class FooTest {
    MyFoo myFoo = new MyFoo();
    void doProtectedFoo() {
        myFoo.pFoo = myFoo.gimmeFoo();
        myFoo.pFoo.doSomeFoo();
    }
}

元のポスターには少し遅れましたが、ちょっと、見つけました。:D

于 2014-12-02T23:59:41.297 に答える
0

インターフェイスを使用して、さまざまな実装クラスによって公開できるメソッドを定義する必要があります。保護されたメソッドとのインターフェースを持つことは、その目的を果たしません。

クラス階層を再設計することで問題を解決できると思います。

于 2012-12-12T13:01:19.303 に答える
0

抽象クラスを作成するだけです。害はありません。

于 2009-01-08T02:44:53.757 に答える
0

継承の代わりにカプセル化を使用できます。

つまり、(何も継承しない) クラスを作成し、その中に拡張するオブジェクトのインスタンスを含めます。

そうすれば、必要なものだけを公開できます。

これの明らかな欠点は、公開するすべてのメソッドを明示的にパススルーする必要があることです。そして、それはサブクラスにはなりません...

于 2009-01-08T02:28:10.140 に答える
0

これを回避する 1 つの方法は、(状況に応じて)protectedまたはprivateスコープを持つインターフェイスを実装する匿名の内部クラスを作成することです。例えば:

public class Foo {
    interface Callback {
        void hiddenMethod();
    }

    public Foo(Callback callback) {
    }
}

次に、のユーザーでFoo

public class Bar {
    private Foo.Callback callback = new Foo.Callback() { 
        @Override public void hiddenMethod() { ... }
    };
    private Foo foo = new Foo(callback);
}

これにより、次のことを回避できます。

public class Bar implements Foo.Callback {
    private Foo foo = new Foo(this);

    // uh-oh! the method is public!
    @Override public void hiddenMethod() { ... }
}
于 2016-04-12T22:53:42.703 に答える