I realise this subject has been covered to death but I am still struggling and could do with some specific help.
My aim is to implement a simple Observer pattern between some kind of observable (lets say a Dog) and some kind of listener (lets say Owner).
Eventually the Owner would be a 'view' and the Dog a 'model' in a MVC paradigm. I am using Dog and Owner just to try and simplify things here.
I have attempted to use Java's built in Observer / Observable classes but have realised how bad the Observers update() method is - it receives a POJO and I would need to check / cast that POJO in the update() method. I would much prefer to have my 'update()' method receive something it can expect.
So, I followed a few tutorials, including this one which uses the Dog/Owner as an example:
http://www.youtube.com/watch?v=qw0zZAte66A
Here I have been shown how to roll my own Observer/Observed classes. In pseudo code, what I now have is this:
Dog/Model {
List listeners;
public fireDogHungryEvent() {
foreach listener {
listener.onDogHungry(this);
}
}
public fireDogPeeEvent() {
foreach listener {
listener.onDogNeedsToPee(this);
}
}
public getHungerLevel() { return hungerLevel; }
public getBladderCapacity() { return bladderCapacity; }
}
Owner/View {
public onDogHungry(model) {
println(model.getHungerLevel());
}
public onDogNeedsToPee(model) {
println(model.getBladderCapacity());
}
}
So now rather than one update() method, I have methods that handle specific events. Brilliant. I am currently happy with the Owner/view class. It knows about the Dog/model's methods and that is fine (I think).
What I do not like is that the Dog/model has references to methods in the Owner/view. I've read countless times and completely agree that a model should not be tightly coupled to its views such as it seems to be above. I am also not keen on all the 'fire' methods in the Dog/model doing nearly the same thing; looping over all it's listeners and just calling a different method on each listener.
Is it possible to decouple this relationship further and not have the Dog/model call specific methods? If so, what is the best way to go about receiving Dog/Model data into the Owner/view and working with it appropriately?
Thanks
You should interface
away knowledge of specific implementation from both the Observer
and the Observable
public enum EventType {
HUNGRY,
PEE;
}
public interface DogEvent {
EventType getType();
}
public interface DogListener {
void fireEvent(DogEvent event);
}
public class Dog {
private final Set<DogListener> listeners = new CopyOnWriteArraySet<DogListener>();
public void register(final DogListener dogListener) {
listeners.add(dogListener);
}
public void unregister(final DogListener dogListener) {
listeners.remove(dogListener);
}
public void firePeeEvent() {
fireEvent(new DogEvent() {
@Override
public EventType getType() {
return EventType.PEE;
}
});
}
public void fireHungryEvent() {
fireEvent(new DogEvent() {
@Override
public EventType getType() {
return EventType.HUNGRY;
}
});
}
private void fireEvent(final DogEvent dogEvent) {
for (final DogListener listener : listeners) {
listener.fireEvent(dogEvent);
}
}
}
public class Owner implements DogListener {
@Override
public void fireEvent(DogEvent event) {
switch (event.getType()) {
case PEE:
System.out.println("Someone take the dog out");
break;
case HUNGRY:
System.out.println("I can't believe the dog is hungry _again_!");
break;
}
}
}
In this case the Dog
does not know about the implementation of the Owner
it just known that the Owner
is a DogListener
.
The Owner
on the other hand does not know about the Dog
it just knows that it has an incoming DogEvent
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With