5

次のようなオブジェクトツリーがあります

           Ball
          /    \
  LegalBall    IllegalBall

そして、私には2つの方法があります:

class o {
AddBall(LegalBall l)
AddBall(IllegalBall i)
}

別のクラスでは、次のことをしたいと思います。

o.AddBall(myBall);

ここで、myBall は Ball 型です。そして、サブタイプに応じて正しいメソッドを呼び出すようにします。どうやら私はこれを行うことはできません... 引数は適用されません。

私が望むものを達成する方法を誰かが知っていますか? または、適切な回避策がある場合

ありがとう

編集:私が構築しようとしているアプリケーションは、クリケット スコアカード タイプのものです。したがって、ボウリングされるボールの種類に応じて、他のさまざまな要素が変化するはずです。

私の当初の意図は、ボールの種類と何らかの形式の UI から得点されるランを指定し、BallFactory から適切な種類のボールを作成できるようにすることでした。たとえば、チームのスコアにボールを送信しないと、値が追加されます。チームのスコアだけでなく、ノーボール カウンターに値を追加します。しかし、同じボールをバッツマン分析に渡して対処すると、バッツマンの合計に値-1しかスコアが付けられません..

私の当初の意図の説明が悪くないことを願っています。

4

7 に答える 7

6

Visitor パターンを使用できます。

class Basket {
    void AddBall(LegalBall l) {
        System.out.println("LegalBall added to basket");
    }

    void AddBall(IllegalBall i) {
        System.out.println("IllegalBall added to basket");
    }
}

interface Ball {
    void AddBall(Basket b);
}

class LegalBall implements Ball {
    void AddBall(Basket b) {
        b.AddBall(this);
    }
}

class IllegalBall implements Ball {
    void AddBall(Basket b) {
        b.AddBall(this);
    }
}

またはそれをより一般的にするために:

interface BallVisitor {
    void visit(LegalBall l);
    void visit(IllegalBall i);
}

interface Ball {
    void accept(BallVisitor v);
}

class LegalBall implements Ball {
    void accept(BallVisitor v) {
        v.visit(this);
    }
}

class IllegalBall implements Ball {
    void accept(BallVisitor v) {
        v.visit(this);
    }
}

class Basket implements BallVisitor {
    void visit(LegalBall l) {
        System.out.println("LegalBall added to basket");
    }

    void visit(IllegalBall i) {
        System.out.println("IllegalBall added to basket");
    }
}
于 2008-12-26T21:46:25.170 に答える
4

実装するメソッドは1 つだけにしてください。

class o {
AddBall(Ball b)
}

そして、異なるクラスに関して異なる振る舞いをするためにポリモーフィズムに頼るようにしてください。もちろん、詳細は Ball 階層の実装に依存します。

于 2008-12-26T21:39:27.510 に答える
0

上記のように、訪問者パターンがあります。Ball、LegalBall、または IllegalBall を変更できない、または変更したくない場合は、ボールの種類に基づいて単一のメソッド ブランチを作成してみてください。後で QuasiLegalBall を追加すると、このコードが壊れることに注意してください。LegalBall と IllegalBall の存在は、記述した 2 つのタイプに適合しないボールが存在することを妨げないため、言及する一般的なケースは困難です (少なくとも言語の観点から)。

class o {
    public void AddBall(Ball b) 
    { 
        if (b instanceof LegalBall) {AddLegalBall(b); }
        else if (b instanceof IllegalBall) {AddIllegalBall(b); }
        else { /*error, new type of ball created*/ }
    }
    private void AddLegalBall(LegalBall b) { }
    private void AddIllegalBall(IllegalBall b) { }
    }
 }
于 2008-12-26T22:12:53.667 に答える
0

訪問者パターン (の一部) が必要な場合 (または必要でない場合) があります。

にメソッドを追加Ball:

public abstract void addTo(o o);

インプリメンテーションインLegalBallおよびIllegalBallアズ

public void addTo(o o) {
    o.add(this);
}
于 2008-12-26T21:42:23.260 に答える
0

訪問者パターンを使用します。せずにそれを行うのは面倒で、この質問の対象でした: Work around Java's static method dispatching without Double Dispatch/Visitor patterns .

ただし、元の問題を教えてください。つまり、なぜ Add メソッドにこれら 2 つのオーバーロードが必要なのですか? 訪問者パターンのような動的ディスパッチに依存する必要のない、まったく別の方法で解決できるのではないでしょうか?

于 2008-12-26T23:05:10.847 に答える
-1

ビジター利用に同意します。

さらに、Ball 階層 (ソース コードへのアクセス) にアクセスできない場合、または単純に何も変更したくない場合。クライアントクラスを変更して、そこから決定できます。

もちろん悪い点は、多くの if/elseif ステートメントで終わることです。

ジェネリック メソッド ( add( Ball ) ) を追加し、そこから他のメソッドを呼び出す必要があります。これは素早く、簡単で、汚れています。

:)

public class Test {
    public static void main( String [] args ) { 
        Ball ball = new IllegalBall();
        Test test = new Test();
        test.add( ball );
        test.add( new IllegalBall() );
        test.add( new LegalBall() );
    }
    private void add( Ball ball ){
        System.out.println("Generic method: I'll have someone handling this : "  + ball );
        if( ball instanceof IllegalBall ) {
            add( ( IllegalBall ) ball );
        } else if( ball instanceof LegalBall ) {
            add( ( LegalBall ) ball );
        }
    }
    private void add( IllegalBall ball ){
        System.out.println("illega-ball: I won't do anything about it! " + ball );
    }
    private void add( LegalBall ball ) { 
        System.out.println("legal-ball: Hey this is legal I'll do my best!! " + ball );
    }
}

class Ball {}
class IllegalBall extends Ball {}
class LegalBall extends Ball {}

ところで、参照を直接持っていない場合、最後の 2 つの呼び出しのように、コンパイラはそれを正しいメソッドに送信します。

ご覧のとおり、次のコードを追加するだけです。

private void add( Ball ball ){
    System.out.println("Generic method: I'll have someone handling this : "  + ball );
    if( ball instanceof IllegalBall ) {
        add( ( IllegalBall ) ball );
    } else if( ball instanceof LegalBall ) {
        add( ( LegalBall ) ball );
    }
}
于 2008-12-26T22:16:31.647 に答える
-1

Visitor パターン、およびコールバックを使用した同様のソリューションは、この場合、欠陥のあるクラス階層をコンパイラに受け入れさせるような方法でコードを曲げようとしているだけのようです。

タイプ Ball を保持し、合法/違法をそのタイプのプロパティにします。いくつかのプロパティに基づいて、またはメソッド、たとえば isLegal() を介して合法/違法をチェックする o.add(Ball) しかありません。

上記のアプローチが合理的ではないように思われる場合、2 つの (非常に) 異なる型を追加する単一の方法を持つことは合理的ではなく、提案したサブタイプの関係は適切ではありません。

于 2008-12-26T22:21:40.203 に答える