0

昨日私はこの質問をしました、そして@JBNizetによって投稿された解決策は完全に機能しました。しかし、その答えと他のいくつかの答え/コメントは、私をまったく別の方向に考えさせました。

基本的に、私は次のクラスを持っています:

  • Load
  • HttpLoad extends Load
  • Target
  • HttpTarget extends Target
  • Controller

Controller仕事はにTarget::fire()あり、どちらが発砲しているのかはLoad気にしません:TargetLoad

// Inside Controller.java
Target target = getTarget();
Load load = getLoad();

target.fire(load);

しかし、私はいつかを書くかもしれません、そして私はでFtpLoad extends Load発砲することができたくありません。したがって、上記の質問の本質は、これをどのように行うかということでした。これに対する答えはジェネリックです。FtpLoadHttpTarget

ただし、回答者が指摘したように、この解決策はLiksovの置換原則に違反しています。他の回答者/コメント提供者は、私が行っていたことが必ずしも良いOOPプラクティスではなかったことを示しているようでした。

だから今私は尋ねています:APIを公開して、不可知論者と不可知論者にControllerなることができますが、それでも、リスコフの置換に違反することなく、適切なサブクラスが適切な型で起動されるように強制しますか?LoadTargetLoadTarget

そして、これを(リスコフに違反せずに)行うことが不可能な場合、このような問題への通常のアプローチは何ですか?前もって感謝します!

4

5 に答える 5

1

HttpTarget.fireパラメータとしてanyを許可する場合、これが可能Loadかどうかを確認するのはその仕事です。したがって、盲目的に呼び出して、指定されたターゲットがその種類の(with )を起動できるかどうかをチェックするか、このチェックを実装して。によって呼び出される関数をすべてに含めます。fireLoadControllerfirefireLoadinstanceofcanFiretargetController

于 2012-09-21T23:05:27.777 に答える
1

ここでのタイピングの問題は、意味的にはbeを要求するという前提条件を強化しようとしているためHttpTarget、のLiskovサブタイプではないというTargetことです。Target#fire(Load)LoadHttpLoad

Target#fire(Load) throws IncompatibleLoadExceptionこれは、常にスローするデフォルトの実装を宣言して持つことで簡単に修復でき、不一致が渡される可能性がControllerあるという事実に対処する必要があります。Load

于 2012-09-21T23:35:04.470 に答える
0

簡単な方法は、コードをチェックインして、クラスが一致していることを確認することです。キーワードを使用してinstanceof、それが正しいクラスであるかどうかを確認できます。

于 2012-09-21T23:03:36.497 に答える
0

前述のように、抽象クラスまたはインターフェースを実装し、instanceofを使用するのが最善です。

抽象クラスの場合:

public abstract class TargetLoad {
    public abstract void fire(TargetLoad i);
}

public class Load extends TargetLoad {
    @Override
    public void fire(TargetLoad i) {
        if (i instanceof Target) return;
        // do fire stuff
    }
}

public class Target extends TargetLoad {
    @Override
    public void fire(TargetLoad i) {
        if (i instanceof Load) return;
        // do fire stuff
    }
}

インターフェース付き:

public interface TargetLoad {
    public void fire(TargetLoad i);
}

public class Load implements TargetLoad {
    @Override
    public void fire(TargetLoad i) {
        if (i instanceof Target) return;
        // do fire stuff
    }
}

public class Target implements TargetLoad {
    @Override
    public void fire(TargetLoad i) {
        if (i instanceof Load) return;
        // do fire stuff
    }
}

コントローラでは、オブジェクトをTargetLoadと呼びます

TargetLoad target = getTarget();
TargetLoad load = getLoad();

target.fire(load);
load.fire(target);
load.fire(load);     //this will do nothing
target.fire(target); //this will do nothing
于 2012-09-21T23:19:35.530 に答える
0

私は、使用を推奨する多数の回答に強く反対しますinstanceof。適切に記述されたOOPコードを使用する必要があることはめったにありません。instanceof使用instanceofすると、通常、コードが扱いにくくなり、保守が困難になります。原則として、instanceof可能な限り避けてください。

あなたが言及した前の質問は、ジェネリックを使用した解決策を提供しました。ここでジェネリックコードを質問から除外したかどうかはわかりません。一般的なコードに戻ります。次に、次のメソッドをドライバーに追加します。

private <L extends Load> void runSuite(TestSuite<L> suite) {
  Target<L> target = testSuite.getTarget();
  L load = testSuite.getLoad();
  target.fire(load);
}
于 2012-09-21T23:42:32.587 に答える