Why Is Java.Util.Observable Not an Abstract Class

Why is java.util.Observable not an abstract class?

As a first approach, one could think that this is done to allow the user to use composition instead of inheritance, which is very convenient if your class already inherits from another class, and you cannot inherit from Observable class also.

But if we look to the source code of Observable, we see that there is an internal flag

private boolean changed = false;

That is checked everytime the notifyObservers is invoked:

public void notifyObservers(Object arg) {
Object[] arrLocal;

synchronized (this) {
if (!changed) return;
arrLocal = obs.toArray();
clearChanged();
}

for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}

But from a class composed by this Observable, we cannot change this flag, since it is private, and the methods provided to change it are protected.

This means that the user is forced to subclass the Observable class, and I would say that the lack of the "abstract" keyword is just a "mistake".

I would say that this class is a complete screwup.

Is java.util.Observable used anywhere?

Observer and Observable are still used in a lot of Eclipse wizard code for detecting when the stuff in input boxes changes, so the wizard itself can be updated. I've had to work with some of this stuff, changing it for our own needs.. :)

Observer Pattern abstract vs interface

Design patterns are meant to be adapted to the particular needs of the applications; they don't prescribe rules set in stone. In particular whether something is an abstract class or an interface is for you to decide, considering all the implications that the decision has for the rest of the application.

That said, interfaces are recommended over abstract classes in general for several reasons. For example abstract classes require you to use inheritance, and in many languages you can't inherit from more than one class. If that's not a problem for your use case, go ahead and use abstract classes if you find them more convenient.

Making a subclass observable in java

I think the Obervable class in java is a fairly poorly thought out class. It really wants to be in interface in my opinion.

However instead of having Person extend from Observable you can use composition at the Passenger level.

Inside your Passenger class you could have code along the lines of this :

private Observable observable = new Observable();

public void addObserver(Observer o) {
observable.addObserver(o);
}

public void notifyObservers() {
observable.notifyObservers();
}

This is a compositional relationship to an observable object. It should work perfectly fine.

More information in this question :

Why is java.util.Observable not an abstract class?

Observer with full transparency

One way would be to use a Decorator instance that holds an ObservableLayer instance and delegates to it.

    final class LayerDecorator implements Layer {
final private ObservableLayer delegate;

public LayerDecorator(ObservableLayer delegate) {
this.delegate = delegate;
}

@Override
public void adjustString(Set<String> strings) {
delegate.adjustString(strings);
delegate.notifyObservers();
}
}

This assumes that calling code is working using references to Layer instead of ObservableLayer.

If calling code has to work using references to ObservableLayer then maybe it is better to refactor ObservableLayer to be an interface having the methods to register listeners, remove them and notify them. This interface also extends the Layer interface.

   interface IObservableLayer extends Layer {
void addObserver(NotifiableLayer layer);
void removeObserver(NotifiableLayer layer);
void notifyObservers();
}

The abstract class ObservableLayer changes to implement IObservableLayer instead of Layer directly. This class remains public to support application classes to define variations of observable layers.

Next an internal decorator for observable layers can be defined as shown below.

    final class ObservableLayerDecorator implements IObservableLayer {
final private ObservableLayer delegate;

public ObservableLayerDecorator(ObservableLayer delegate) {
this.delegate = delegate;
}

@Override
public void addObserver(NotifiableLayer layer) {
delegate.addObserver(layer);
}

@Override
public void removeObserver(NotifiableLayer layer) {
delegate.removeObserver(layer);
}

@Override
public void notifyObservers() {
delegate.notifyObservers();
}

@Override
public void adjustString(Set<String> strings) {
delegate.adjustString(strings);
this.notifyObservers();
}
}

Please note how the notification is done in this case.

Now instances of IObservableLayer can be created as

    IObservableLayer observableLayer = new ObservableLayerDecorator(new MyClass());

Factory methods will be helpful here as they can be defined to handle creation of various application-level observable layer classes so that the instances can be created consistently that return an IObservableLayer which is decorated. That will free up developers from knowing how to use the decorator and allow the decorator to be an internal utility.

Java Observer and Observable not working properly between applications

Have you called addObserver on Comanda and added the MainController as an Observer? Also, when the change occurs are you calling setChanged and notifyObservers?

Looking at the code you have posted I can see that you have not wired the Observer and Observable Objects together. As I said, you have to call addObserver on your Observable object, then within your Observable Object, whenever a change is made you need to call setChanged then notifyObservers. Only when notifyObservers is called will the update method of any Observers that have been added be called.

You said in your question that when you delete one record the list doesn't update, which makes me think that Comanda is probably not the Object that you want to Observe. Whichever Object it is that holds the List of records is the one that should be the Observable.

Have a look at this for some more information on the Observer/Observable pattern.

When should we use Observer and Observable?

You have a concrete example of a Student and a MessageBoard. The Student registers by adding itself to the list of Observers that want to be notified when a new Message is posted to the MessageBoard. When a Message is added to the MessageBoard, it iterates over its list of Observers and notifies them that the event occurred.

Think Twitter. When you say you want to follow someone, Twitter adds you to their follower list. When they sent a new tweet in, you see it in your input. In that case, your Twitter account is the Observer and the person you're following is the Observable.

The analogy might not be perfect, because Twitter is more likely to be a Mediator. But it illustrates the point.

Observer is deprecated in Java 9. What should we use instead of it?

Why is that? Does it mean that we shouldn't implement observer pattern anymore?

Answering the latter part first -

YES, it does mean you shouldn't implement Observer and Obervables anymore.

Why were they deprecated -

They didn't provide a rich enough event model for applications. For example, they could support only the notion that something has changed, but didn't convey any information about what has changed.

Alex's answer puts it nicely upfront that Observer has a weakness: all Observables are the same. You have to implement the logic that is based on instanceof and cast object to concrete type into Observable.update() method.

To add to it there were bugs like one could not serialize the Observable class because as it didn't implement Serializable interface and all of its members were private.

What is a better alternative to that?

On the other hand Listeners have a lot of types and they have callback methods and don't require casting. As pointed by @Ravi in his answer you can make use of PropertyChangeListener instead.

For the rest of it the @Deprecation has been marked with proper documentation to explore other packages as linked in other answers as well.


Note that the deprecation was also marked with an analysis as stated in this mail -

These days, anyone encountering these is probably hitting them by
mistake while using RxJava or other reactive-stream frameworks. In
which case, users will normally want to instead use the jdk9
java.util.concurrent.Flow APIs that all reactive-streams frameworks
should be compatible/interoperable within their planned upcoming
jdk9-compatible versions.

Edit: It's also worth mentioning that the deprecation of the APIs is not primarily just because of the above reason, but also being unable to maintain such legacy code as mentioned in comments of a few of the bug reports (linked above) which were raised to mark an improvement in its implementation in one or another way.



Related Topics



Leave a reply



Submit