Javaのリスナーを継承
-
21-08-2019 - |
質問
いるjavaクラスで火災のカスタムjavaのイベント。の構造のコードは次の通りです:
public class AEvent extends EventObject {
...
}
public interface AListener extends EventListener {
public void event1(AEvent event);
}
public class A {
public synchronized void addAListener(AListener l) {
..
}
public synchronized void removeAListener(AListener l) {
..
}
protected void fireAListenerEvent1(AEvent event) {
..
}
}
全てが正常に動作してしまいましたが、まず私が新しいクラスのサブクラスA(ここではB)、火災の新しいイベントです。私が考える以下の変更:
public class BEvent extends AEvent {
...
}
public interface BListener extends AListener {
public void event2(BEvent event);
}
public class B extends A {
public synchronized void addBListener(BListener l) {
..
}
public synchronized void removeBListener(BListener l) {
..
}
protected void fireBListenerEvent2(AEvent event) {
..
}
}
これは正しいアプローチを考えていますか。また、ウェブの事例が見当たらない。
がよくないと思う次回のプレゼンテーション:
BListener
二つの方法が用AEvent
その他の用途BEvent
としてのパラメータとします。B
クラスの両方がaddAListener
やaddBListener
ます。う隠addAListener専用キーワード? [更新ではできない非表示専用キーワード]- 類似の問題
fireAListenerEvent1
やfireBListenerEvent1
ます。
私が使っているJavaのバージョン1.5.
解決
私はBListener
がAListener
を拡張する必要がある理由は表示されません。
あなたは本当にもB
を実装するためにevent1()
イベントに興味を持って全員を強制しますか?
また、あなたは、 そして最後の発言として、私はaddAListener()
を追加することはできません。また、href="http://en.wikipedia.org/wiki/Liskov_substitution_principle"リスコフの置換原則の(すべてのB必見のrel="noreferrer">あなたがする必要はありませんか、
fire*()
法が保護作ると思います。公共および公共のメンバーの数は、あなたのパブリックインターフェイスを清潔に保つ軽減それらを保つために、まったく理由は通常ありません。
他のヒント
それはあなたが望むものではないですし、デザインを変更するには脆く、困難につながる、継承を使用しないでください。この組成物は、より柔軟性とデザインのためのより良いアプローチです。常に彼らがイベントを変更する必要はありませんので、できるだけ粒状としてのインタフェースを設計してみてください。彼らは、システムの他の部分との契約です。新しい機能は、最初のオプションを追加する必要がある場合にはイベントへのより多くの情報を追加することです。それが適切でない場合は、そのイベントを配信するための新しいインターフェイスを設計する必要があります。これは影響されない、任意の既存のコードを変更することが防止される。
ここでは、このための私の好きなパターンですが、私はそれは、一般的にオブザーバーと呼ばれます信じています。
そのイベントのタイプ(fooEvent()addFooEventListener()removeFooEventListener())のためのメソッドを定義する新しいインターフェイスを作成します。これらのイベントを発生させる具体的なクラスで、このインタフェースを実装します。 (私は通常などSourcesFooEvent、FiresFooEvent、FooEventSource、のようなこの何かを呼び出します)。
あなたはコードの重複を削減したい場合は、リスナーの登録を処理するヘルパークラスを作成することができ、コレクションに格納し、イベントを公開するため、火災の方法を提供しています。
ジェネリックはここに助けることができます。まず、一般的なリスナーインタフェースます:
public interface Listener<T> {
void event(T event);
}
次に、マッチングのEventSourceインターフェース
public interface EventSource<T> {
void addListener(Listener<T> listener);
}
最後に抽象基底クラスはすぐにリスナーとイベントディスパッチの登録を処理するためのヘルパークラスを作成します。
public abstract class EventDispatcher<T> {
private List<Listener<T>> listeners = new CopyOnWriteArrayList<T>();
void addListener(Listener<T> listener) {
listeners.add(listener);
}
void removeListener(Listener<T> listener) {
listeners.remove(listener);
}
void fireEvent(T event) {
for (Listener<T> listener : listeners) {
listener.event(event);
}
}
}
あなたは、任意の特定のクラスを拡張することを必要としない一方で、他のクラスは簡単のEventSourceを実装することができ、カプセル化による抽象のEventDispatcherを利用すると思います。
public class Message {
}
public class InBox implements EventSource<Message> {
private final EventDispatcher<Message> dispatcher = new EventDispatcher<Message>();
public void addListener(Listener<Message> listener) {
dispatcher.addListener(listener);
}
public void removeListener(Listener<Message> listener) {
dispatcher.removeListener(listener);
}
public pollForMail() {
// check for new messages here...
// pretend we get a new message...
dispatcher.fireEvent(newMessage);
}
}
うまくいけば、これは、型の安全性(重要)、柔軟性とコードの再利用の間に素晴らしいバランスを示します。
私はBを発射すると、自動的に発動することSAUAするあなたのコメントから理解しています。
なぜリスナーのシングルタイプを使用して、いくつかの継承、委任とジェネリック医薬品を混在させない?
class AEvent {}
class BEvent extends Event{}
interface EventListner<E extends AEvent>
{
onEvent(E e);
}
class ListenerManager<E extends AEvent>{
addListner(EventListener<? extends E>){}
removeListner(EventListener<? extends E>){}
fire(E e);
}
class A extends ListenerManager<AEvent>
{
}
class B extends ListenerManager<BEvent>
{
A delegatorA;
@Override addListener(EventListener<? extends BEvent> l)
{
super.addListner(l);
delegatorA.addListener(l);
}
@Override removeListener(EventListener<? extends BEvent> l)
{
super.removeListner(l);
delegatorA.removeListener(l);
}
@Override fire(BEvent b)
{
super.fire(b);
a.fire(b)
}
}
説明:リスナーを管理するためのコードは、基本クラスのリスナーManagerで、共有されています。 Bはコンパイル時にチェックするためにジェネリック医薬品のBListenersを受け取ることができます。 Bを発射すると、自動的に起動します。
ていて思ったときにも非常に簡単です。
私understading
おついての基本的なクラス A を処理する basicOperation
というのは具体的なサブクラス B このほか、を行う場合があり specificOperations
そうなるとする両イベントの取り扱い( 基本 ために、 基本 + 特定の B)
、こちらをクリックして下さいな過負荷になるとのことだけで追加特定のハンドラ(またはリスナー)特定のイベント。
この場合、イベントが"基本"と。
そのイベントは、必要なものが反応します。では、どう思いるので、これまでにチェック に 特定のリスナーを識別する 特定の イベントのようになります:
if( whichEvent instanceof SpecificEvent ) {
SpecificEvent s = ( SpecificEvent ) whichEvent;
// Do something specific here...
}
ことになるのです。
ご説明の問題は、抽象的、具体的な解決策が考えられる。ただ、これからも頑張ってく説明する"想い"いかがでしたでしょうを再解析の問題です。
が私の理解で正しい(その対応する必要がある 基本 + 特定の 一回)の長時間の以下のコードがあります。
ベストについて
import java.util.*;
class A {
// All the listener will be kept here. No matter if basic or specific.
private List<Listener> listeners = new ArrayList<Listener>();
public void add( Listener listener ) {
listeners.add( listener );
}
public void remove( Listener listener ) {
listeners.remove( listener );
}
// In normal work, this class just perform a basic operation.
public void normalWork(){
performBasicOperation();
}
// Firing is just firing. The creation work and the
// operation should go elsewhere.
public void fireEvent( Event e ) {
for( Listener l : listeners ) {
l.eventHappened( e );
}
}
// A basic operation creates a basic event
public void performBasicOperation() {
Event e = new BasicEvent();
fireEvent( e );
}
}
// Specialized version of A.
// It may perform some basic operation, but also under some special circumstances
// it may perform an specific operation too
class B extends A {
// This is a new functionality added by this class.
// Hence an specifi event is fired.
public void performSpecificOperation() {
Event e = new SpecificEvent();
// No need to fire in different way
// an event is an event and that's it.
fireEvent( e );
}
// If planets are aligned, I will perform
// an specific operation.
public void normalWork(){
if( planetsAreAligned() ) {
performSpecificOperation();
} else {
performBasicOperation();
}
}
private boolean planetsAreAligned() {
//return new Random().nextInt() % 3 == 0;
return true;
}
}
// What's an event? Something from where you can get event info?
interface Event{
public Object getEventInfo();
}
// This is the basic event.
class BasicEvent implements Event{
public Object getEventInfo() {
// Too basic I guess.
return "\"Doh\"";
}
}
// This is an specific event. In this case, an SpecificEvent IS-A BasicEvent.
// So , the event info is the same as its parent. "Doh".
// But, since this is an SpecificEvent, it also has some "Specific" features.
class SpecificEvent extends BasicEvent {
// This method is something more specific.
// There is no need to overload or create
// different interfaces. Just add the new specific stuff
public Object otherMethod() {
return "\"All I can say is , this was an specific event\"";
}
}
// Hey something just happened.
interface Listener {
public void eventHappened( Event whichEvent );
}
// The basic listner gets information
// from the basic event.
class BasicEventListener implements Listener {
public void eventHappened( Event e ) {
System.out.println(this.getClass().getSimpleName() + ": getting basic functionality: " + e.getEventInfo());
}
}
// But the specific listner may handle both.
// basic and specific events.
class SpecificListener extends BasicEventListener {
public void eventHappened( Event whichEvent ) {
// Let the base to his work
super.eventHappened( whichEvent );
// ONLY if the event if of interest to THIS object
// it will perform something extra ( that's why it is specific )
if( whichEvent instanceof SpecificEvent ) {
SpecificEvent s = ( SpecificEvent ) whichEvent;
System.out.println(this.getClass().getSimpleName() + ": aaand getting specific functionality too: " + s.otherMethod() );
// do something specific with s
}
}
}
// See it run.
// Swap from new A() to new B() and see what happens.
class Client {
public static void main( String [] args ) {
A a = new B();
//A a = new A();
a.add( new BasicEventListener() );
a.add( new SpecificListener() );
a.normalWork();
}
}
サンプル出力:
BasicEventListener: getting basic functionality: "Doh"
SpecificListener: getting basic functionality: "Doh"
SpecificListener: aaand getting specific functionality too: "All I can say is , this was an specific event"
まさきもなく、インターフェイスで簡単に
の場合
public class BEvent extends AEvent {
...
}
public interface BListener extends AListener {
public void event2(BEvent event);
}
あなたは次のようなsomethinを行うことはできません
public class B extends A {
@Override
public synchronized void addAListener(AListener l) {
if (l instanceof BListener) {
...
} else {
super.addAListener(l);
}
}
...
}
私がコメントで言ったように、私はあなたが実際に達成したいかわからないんだけど?どこから呼び出され、それが呼び出されるとき、何それは何をする必要がありますか?
誰に基づくさんの情報をまとの関係について A
& B
, だと思っていくる BListener
aサブインタフェースの AListener
.その名の通り、 BListener
はと聞くために BEvent
s、 既に クラスのサブクラス AEvent
s.のための明確性、リスナーは目の肥えた目的のな重ねぎ.また、必要がないような重複するリスナーから今まで既に定義が別の方法でクラス B
取扱いの異なる種類のリスナー.
例えば、この例では、ターコード:
public class MovableMouseEvent extends EventObject
public class ClickableMouseEvent extends MovableMouseEvent
public interface MovableMouseListener extends EventListener
// mouseMoved(MovableMouseEvent)
public interface ClickableMouseListener extends MovableMouseListener
// mouseClicked(ClickableMouseEvent)
public class MovableMouseWidget
// {addMovableMouseListener,removeMovableMouseListener}(MovableMouseListener)
// fireMovableMouseEvent(MovableMouseEvent)
public class ClickableMouseWidget extends MovableMouseWidget
// {addClickableMouseListener,removeClickableMouseListener}(ClickableMouseListener)
// fireClickableMouseEvent(ClickableMouseEvent)
このデザイン作品では分かりにくい ClickableMouseListener
取り扱う二種類のイベント ClickableMouseWidget
取り扱う二種類のリスナーにとんだを正しく指摘しなければなりません。現在、以下の代替用組成物の代わりにつ
public class MouseMoveEvent extends EventObject // note the name change
public class MouseClickEvent extends EventObject // don't extend MouseMoveEvent
public interface MouseMoveListener extends EventListener
// mouseMoved(MouseMoveEvent)
public interface MouseClickListener extends EventListener // don't extend MouseMoveListener
// mouseClicked(MouseClickEvent)
public interface MouseMoveObserver
// {addMouseMoveListener,removeMouseMoveListener}(MouseMoveListener)
// fireMouseMoveEvent(MouseMoveEvent)
public interface MouseClickObserver
// {addMouseClickListener,removeMouseClickListener}(MouseClickListener)
// fireMouseClickEvent(MouseClickEvent)
public class MovableMouseWidget implements MouseMoveObserver
public class ClickableMouseWidget implements MouseMoveObserver, MouseClickObserver