Java関数のパラメーターにオプションのインターフェースが必要ですか?


8

Java(バージョン8)には2つのインターフェースがあり、非常によく似ています。インターフェイスを変更したり、それらを実装するクラスを変更したりすることはできません。

public interface A {
    int get();
}

public interface B {
    int get();
    int somethingelse();
}

今、私はその実装が両方のインターフェースに(ほぼ)フィットする関数を持っています。私はそれがそのようなことをしたいと思っています:

public int foo((A | B) p) {
    int ret = 0;
    if (p instanceof B) {
        ret = p.somthingelse();
    }
    return ret + p.get();
}

この関数はプログラムのメインパイプラインにあるため、インスペクションを使用したくありません。良い性能が欲しいです。Javaでこれを行うことは可能ですか?

編集:

簡単な解決策は、コピー/貼り付けしてfoo()、インターフェイスごとに異なる方法で実装することです。しかし、実際foo()には、インターフェースはそれよりもはるかに長く、コードの重複を避けようとしています。


2
AとBには共通点はありません。したがって、2つのfoo()メソッドを作成します。1つはBを受け取り、もう1つはAを受け取ります。また、パフォーマンスの問題が発生するまで、パフォーマンスの問題の原因を推測せず、測定によってこの仮定を確認します。 。
JB

@JBNizet AとBはget()共通しています。これはもちろん単純化された例です。実際には、それらはより多くの機能を共有しています。
Liran Funaro

1
いいえ、ありません。BはAを拡張しません。そのため、同じシグネチャと戻り値の型を持つメソッドがあるだけです。すべてのBがAであると仮定されている場合、BはAを拡張する必要
JB Nizet

1
@ user2478398 ernest_kの回答を見ましたか?それはあなたが話していることだと思います。
Liran Funaro

1
@LiranFunaroそれら(両方のインターフェース)に共通点がある場合は、それを親に抽出してさらに拡張してみませんか?余談ですが、publicアクセサはインターフェイスメソッドに対して冗長です。そして、instanceof代わりにimplements
ナマン

回答:


4

残念ながら、関係のない2つのタイプ間にそのような遡及的な関係を作成する方法はありません。

変更foo()とその呼び出しが可能な場合は、内部で呼び出すシグネチャと一致する機能インターフェースを利用できる可能性がありますfoo。私が使用しているIntSupplierの具体的な実装を使用してラムダ式を対応して、ここAB

次の実装があるとします。

class AImpl implements A {
     //implementation
}
class BImpl implements B {
     //implementation
}

foo次のようなものに変更できます。

public int foo(IntSupplier get, IntSupplier somethingElse) {
    int ret = 0;
    if (somethingElse != null) {
        ret = somethingElse.getAsInt();
    }
    return ret + get.getAsInt();
}

そしてそれをこのように呼びます:

A a = new AImpl();
B b = new BImpl();

int result = this.foo(a::get, b::somethingelse);

興味深い解決策!これは、fooの署名の変更を必要としないソリューションに拡張できます。foo()インターフェースごとにに2つの実装を記述foo()し、一致するサプライヤーに連絡します。これを追加しますか、それとも回答を編集しますか?
Liran Funaro

1
@LiranFunaroそうですね。ifロジックを内部に残さなければならないという制約によって制限されましたfoo()。しかし、はい、それが適切であれば、間違いなくそれを行うことができます。
ernest_k

1
申し訳ありませんが、質問とIntSupplierこの回答の提案に関連することはほとんどありません。さらに、BImpl(または単にB)複数の抽象メソッドが指定されていると、FunctionalInterfaceとして使用できません。さらに、コメントから2つの無関係なタイプ」というステートメントは当てはまりません。Nitpick:IntSupplier getコードでは使用されません。
ナマン

1
@ナマンあなたの意見をありがとう。B機能的なインターフェイスとして使用されていません。この場合のb:somethingelseメソッドリファレンスですIntSupplier(コードをコンパイルすることをお勧めします)。そして、はい、AおよびB2つの完全に無関係な種類があります。全体的なソリューションについては、少し厄介だと思います。より細かいアプローチはあると思いますが、OPが提供できないリファクタリングを回避するものは多くありません。
ernest_k

3

私が想像できる唯一の方法はこれです:

public int foo(A p) {
    return internal_foo(p);
}

public int foo(B p) {
    return internal_foo(p);
}

private int internal_foo(Object p) {
    if (p instanceof A) {
        return ((A)p).get();
    }
    if (p instanceof B) {
        B b = (B)p;
        ret = b.somthingelse();
        return ret + b.get();
    }
    throw new ClassCastException("Wrong type");
}

ありがとう。これの問題は、関数の実装がそれよりもはるかに長いことです。だから私はたくさんのコードをコピーして貼り付ける必要があります。それは私が避けようとしていることです:)
Liran Funaro

2

Afaik、Javaはこれを直接サポートしていませんが、手動で「タイプユニオンラッパー」を作成することもできます。このようなもの:

abstract class AorB {
    public static AorB wrap(A a) {
        return new AWrapper(a);
    }

    public static AorB wrap(B b) {
        return new BWrapper(b);
    }

    abstract int get();
    abstract int somethingElse();
}

class AWrapper extends AorB {
    private final A a;

    AWrapper(A a) {
        this.a = a;
    }

    @Override
    int get() {
        return a.get();
    }

    @Override
    int somethingElse() {
        return 0;
    }
}

class BWrapper extends AorB {
    private final B b;

    BWrapper(B b) {
        this.b = b;
    }

    @Override
    int get() {
        return b.get();
    }

    @Override
    int somethingElse() {
        return b.somethingElse();
    }
}

// and then

public int foo(A a) {
    return fooImpl(AorB.wrap(a));
}

public int foo(B b) {
    return fooImpl(AorB.wrap(b));
}

int fooImpl(AorB p) {
    return p.get() + p.somethingElse();
}

上記のhasSomethingElse()ように、返す適切なデフォルト値がない場合は、などの検査関数を追加することもでき0ます。


私が2つの答えを受け入れることができれば、私もこの答えを受け入れます。
Liran Funaro
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.