2010-12-11 4 views
7

私は以前この質問をしましたが、問題自体ではなく、ほとんどの人が拾ったコードに間違いがありました。Java:メソッドをオーバーライドするときにパラメータのサブクラス/サブタイプに置き換えますか?

とにかく、クラスのインターフェイスメソッドをオーバーライドしようとしています。ただし、オーバーライドされたメソッドのパラメータの型を、オーバーライドされたメソッドで定義されているパラメータの型のサブクラスにしたいとします。

インタフェースである:

public interface Observer { 
public void update(ComponentUpdateEvent updateEvent) throws Exception; 
} 

このメソッドをオーバーライドするクラスがあるが:

public class ConsoleDrawer extends Drawer { 

//... 

@Override 
public void update(ConsoleUpdateEvent updateEvent) throws Exception { 
    if (this.componentType != updateEvent.getComponentType()) { 
    throw new Exception("ComponentType Mismatch."); 
    } 
    else { 
    messages = updateEvent.getComponentState(); 
    } 
} 

//... 

} 

ConsoleUpdateEventはComponentUpdateEventのサブクラスです。

これで、ConsoleDrawerのupdate()メソッドをComponentUpdateEventをパラメータとして取得し、それをConsoleUpdateEventにキャストすることができましたが、可能であれば、より洗練されたソリューションを探しています。 Anyhelpに感謝します。ありがとうございました。

+5

これは、インターフェースの原則(つまり、インターフェースを実装するクラスは、インターフェースによって指定されたすべてのメソッドのシグネチャーと正確に一致します)とは反対に、これは可能ではないと思います。しかし、他の人が私を間違っているかどうかを知ることに非常に興味があるので、私はこの質問を見るでしょう。 – DGH

答えて

2

以下を試すことができます。 @Deprecatedは、コンパイラが2番目ではなく最初のメソッドを呼び出すことを知っている場合に警告を生成します。

@Override @Deprecated 
public void update(ComponentUpdateEvent updateEvent) { 
    // throws a ClassCastException if its not the right type. 
    update((ConsoleUpdateEvent) updateEvent); 
} 

public void update(ConsoleUpdateEvent updateEvent) { 
    messages = updateEvent.getComponentState(); 
} 

ところで:あなただけがすべてに例外がスローされます置くべきではありません。確かにベストプラクティスではありません。

EDIT:私はOSGiでうまく動作しますが、どこでも働くことができるこの問題に対する別のソリューションを実装しました。

オブザーバは、ブローカに自身を登録し、ObserverCallbackなどのアノテーションを持つメソッドを見つけることを期待しています。

public class ConsoleDrawer extends Drawer { 
@ObserverCallback 
public void onConsoleUpdateEvent(ConsoleUpdateEvent updateEvent) { 
    messages = updateEvent.getComponentState(); 
} 
} 

public class DeviceDrawer extends Drawer { 
@ObserverCallback 
public void onDeviceUpdateEvent(DeviceUpdateEvent updateEvent) { 
    // do something. 
} 
} 

最初のケースでは、ブローカは1つの引数を取る@ObserverCallbackを持つメソッドを見つけます。これはブローカーが渡す唯一のタイプです。 2番目のクラスは異なるタイプを予期しています。オブザーバは、複数のメソッド/タイプを持つことができ、それぞれのタイプに適した異なるメソッドで異なるメッセージを扱うことができます。あなたは、あなたが期待していないデータ型を受け取ることは決してないことも知っています。

+0

個人的に(私が話したことのある他の多くの人は)元の意図以外にDeprecatedタグを使用することを嫌っていました。以前は有効であったが、廃止予定のメソッドをマーキングしています。このような何かのためにそれを使用することは、ハッカーっぽさを感じる。 – DGH

+0

@DGH、このメソッドは(以前は親に対して)有効でしたが、このクラスではもはや有効ではありません。 ;)私はあなたのポイントを取る。理想的には、コンパイラエラーを生成するタグが存在します。すべての実装が契約を尊重するようにupdate()メソッドを設計する方がよいでしょう。 –

+0

提案していただきありがとうございます。最初のソリューションを使用します。 2番目の更新メソッドの名前をprivate void addEventMessages(ConsoleUpdateEvent){// ...}に変更しました。これは合理的にうまくいくようです。 – carnun

7

できません。これはエッフェルではありません。問題は、インターフェイスを使用して互換性のない型で実装メソッドを呼び出すことができることです。したがって、共変パラメータは許されません。 contravariantパラメータは許可されませんが、過負荷を提供する方が簡単です。共変リターン型は許可されています(1.5以降)。あるいは、

public interface Observer<T extends ComponentEvent> { 
    void update(T event) throws Exception; 
} 

より意味のあるインタフェースを使用します:

あなたがインターフェイスをparameterise可能性がOOPの原則によって行く

public interface ConsoleObserver { 
    void update(ConsoleEvent event) throws Exception; 
} 
+1

詳しい解答はこちらhttp://stackoverflow.com/a/9421315/1276636 – Sufian

2

を、サブクラスが全く同じように使用可能でなければなりません親クラス。例: Javaはメソッドをオーバーライドするときに、パラメータのサブタイプを使用することを許可した場合

Observer ob = new ConsoleDrawer(); 
ob.update(new ComponentUpdateEvent()); // This needs to work always. 

しかし、それは((サブクラスで)オーバーライドメソッドは、入力パラメータを拒否しケースにあなたのコードを公開します上記の場合ComponentUpdateEvent)。したがって、Observerリファレンスでupdate()を呼び出すかどうかを安全に判断することは決してできません。

したがって、唯一の論理的な解決策は、親クラスのパラメータを受け入れ、タイプチェックしてから必要なサブタイプにキャストすることです。

関連する問題