tags:

views:

288

answers:

5

I am learning java and i want to make my class into an observable class. However I already have it extending another class. What do I do?

A: 

Multiple inheritance (to extend two classes) is not possible in Java. Is considered a bad design in almost all cases.

If you give us some more information, maybe somebody can help you a little more.

Sinuhe
+1  A: 

Java doesn't allow multiple inheritance, so there is no direct way to do it. You should consider using a delegate pattern having your main object that delegates his observer behaviour to an another object..

class YourObject extends ItsAncestorClass
{
      private Observer includedObserver;

      public Observer getHisObserver(..)
}

Another approach would be turning the object from which your class is extending to an interface, then you'll be allowed to extend from Observer.

Jack
@finnw - and Jack never said anything about Observer not being an abstract class.
weiji
A: 

Use a bridge.

Create a class that extends Observable that the first class just calls the methods of the second class.

Bridge method detail:

 public class XXX {
    public class XXXObservableBridge : Observable {
       public void RaiseEvent();
       // Listeners etc
    }

    private XXXObservableBridge ObservableBridge;

    XXX() {
       ObservableBridge = new ObservableBridge;
    }

    public Observable AsObservable() { return ObservableBidge; }

    public void RaiseEvent() { ObservableBridge.RaiseEvent(); }
 }
Joshua
-1 this is a Java question, not C#. Please stick to Java syntax and APIs
finnw
@finnw C# has no need for the observable/observer pattern and my code doesn't even call any API functions.
Joshua
There isn't an IObservable in Java, and even if you defined one, java.util.Observable does not implement it.
Stephen C
+8  A: 

I'd recommend avoiding using the Obserable class altogether, but rather define event-specific listeners and corresponding event definitions. Then define a list of listeners within your class along with methods to add and remove listeners, and propagate events to them (see below).

Observable forces you to use java.lang.Object to represent events and then check the event type using instanceof, which is an ugly non-OO approach, and makes the code more difficult to understand. If you look at the classes within the javax.swing package you'll see they avoided using Observer / Observable altogether and used an approach similar to the below.

Event Definition

public class MyChangeEvent extends EventObject {
  // This event definition is stateless but you could always
  // add other information here.
  public MyChangeEvent(Object source) {
    super(source);
  }
}

Listener Definition

public interface MyChangeListener {
  changeEventReceived(MyChangeEvent evt);
}

Class Definition

public class MyClass {
  // Use CopyOnWriteArrayList to avoid ConcurrentModificationExceptions if a
  // listener attempts to remove itself during event notification.
  private final CopyOnWriteArrayList<MyChangeListener> listeners;

  public class MyClass() {
    this.listeners = new CopyOnWriteArrayList<MyChangeListener>();
  }

  public void addMyChangeListener(MyChangeListener l) {
    this.listeners.add(l);
  }

  public void removeMyChangeListener(MyChangeListener l) {
    this.listeners.remove(l);
  }

  // Event firing method.  Called internally by other class methods.
  protected void fireChangeEvent() {
    MyChangeEvent evt = new MyChangeEvent(this);

    for (MyChangeListener l : listeners) {
      l.changeEventReceived(evt);
    }
  }
}
Adamski
java.util.Observable also has a flag to indicate whether anything has changed. And sometimes a new Event class is overkill.
finnw
+1 for using CopyOnWriteArrayList
finnw
@finnw - Most of my event class definitions are < 10 lines of autogenerated code and take seconds to write. However, in situations where I wish to avoid defining new event classes I favour PropertyChangeEvent / PropertyChangeListener / PropertyChangeSupport where at least you can inspect the property name before attempting any casts.
Adamski
CopyOnWriteArrayList is unnecessary - just explicitly copy on read or write. `PropertyChangeListener` is a bit of a mess. `javax.swing.event.ChangeListener` is a clean, something just changed. In fact ignoring event objects makes things even cleaner (in reality they don't carry useful information for change events, as opposed to input events).
Tom Hawtin - tackline
CopyOnWriteArrayList is needed unless you want to synchronize the fireChangeEvent, addMyChangeListener, and removeMyChangeListener methods or get a java.util.ConcurrentModificationException if you add/remove while the for loop is running. If the list isn't frequently added/removed from (and probably isn't in most cases) the COpyOnWriteArrayList is probably better.
TofuBeer
+1 for CopyOnWriteArrayList. Getting reentrant semantics right is a pain without it and it's more efficient than always copying.
Dave Ray
I'm not sure it is more efficient than always copying (even on read). I'm pretty sure it doesn't make many difference in terms of CPU cycles, but will use more memory and therefore more GC cycles. If you copy on read you also get to spend cycles at non-critical times.
Tom Hawtin - tackline
Personally I'd go with synchronized and be done with it. No copying and only really a performance problem if things are happening with a high frequency.
TofuBeer
@Tom: I don't understand the argument in copying the list for all reads and writes where, with CopyOnWriteArrayList you have a more efficient implementation in that the list is only copied when a listener is added or removed, but not when firing an event (likely to be the common case).
Adamski
@TofuBeer: synchronizing on all methods will not work: If a call is made to fireChangeEvent() and a listener is notified and attempts to remove itself this will still cause a ConcurrentModificationException because the thread doing the notifying *already holds the object lock* and hence can call removeChangeListener *without blocking*.
Adamski
@Tom: I agree with you re. ChangeListener in that it's cleaner / simpler - I use this where possible but am often dealing with complex UI panels where where PropertyChangeListener is more useful. Also, if I bind to a specific property name it's a lot clearer in the code IMHO.
Adamski
`CopyOnWriteArrayList` was quite clearly written for *exactly this sort of thing*. Adding listeners is infrequent and yet it provides safe iteration and removes the need to have complex logic to handle the case where the processing of an event by the listener attempts to add/remove listeners
oxbow_lakes
@Adamski I've been programming in Java since 1995 and have yet to see a real world case where that happens... in face I would consider the code broken if it tried to do that... but yes it could.
TofuBeer
@TofuBeer: For the sake of typing CopyOnWriteArrayList rather than ArrayList I would say it's worth avoiding the risk that it may happen. I agree that it's a rare event but we have seen it in applications that dynamically add / remove many listeners over the application's life-time.
Adamski
In the MyChangeEvent class, "super(this);" should be "super(source);"
Jeremy Ross
A: 

Another option is to wrap your object in an Observable object.

public class MyObjectObservableWrapper implements Observable {  
  private MyObject myObject;
  public MyObjectObservaleWrapper(MyObject myObject){
    this.myObject = myObject;
  }
  // interface methods here
}

This option works when the data to be used by the Observable methods is accessible through public methods of MyObject. So, it may not be suitable for all cases.

Chuck Deal