What is the problem with implementing the Observer pattern without base classes/interfaces, just with Runnable for example:
public ObservableClass
{
List<Runnable> observers;
public void add(Runnable r) { observers.add(r); }
public void notify() { // forloop and observers[i].run(); }
}
public ObserverClass
{
ObservableClass observable;
public void listen()
{
observable.add(new Runnable() {
#Override
public void run() {
// do something here
}
});
}
}
I'm asking for problems beside if this is "ugly" or "lazy".
For example one problem I can see is that we cannot pass data to the observer directly (but if we have access to that data in Observable then we could still use it inside our RUnnable).
What are the disadvantages of using a code like that instead of creating an Observable base class and some Observer interface?
Related
In doing some restructuring on a project of mine, I've been attempting to better utilise object oriented concepts in my code but I'm not sure how to structure this particular situation:
A method can trigger one of three possible "events", with each event having a dependency on a particular type (Player, Block, World) which needs to happen at runtime as they are deserialised from a file. In an attempt to simplify the execution path I structured it like this so they can all be part of a List which just executes a single method:
public interface IEvent {
void trigger();
}
public class PlayerEvent implements IEvent {
private Player player;
public void passPlayer(Player player){
this.player = player;
}
public void trigger(){
// player does things
}
}
public class BlockEvent implements IEvent {
private Block block;
public void passBlock(Block block){
this.block = block;
}
public void trigger(){
// block does things
}
}
However, since each event is dependent on a Player or Block depending on its type, I would have to iterate over the list and downcast each object using instanceof to pass the relevant dependency.
public void executeEvents(){
for(IEvent event : events){
if(event instanceof PlayerEvent){
((PlayerEvent) event).passPlayer(player);
} else {
((BlockEvent) event).passBlock(block);
}
event.trigger();
}
}
I read that downcasting should never be done under any circumstances, so I've been wondering what alternatives I could use that would follow a similar simple execution path but falls under good OOP practice? Or should I just eliminate the interface altogether and have a separate List for each event type?
I read that downcasting should never be done under any circumstances,
so I've been wondering what alternatives
I would not generalize. Applications/libraries that generate code or use reflection generally may use downcast.
In other cases, downcast should indeed be avoided.
You have multiple ways to achieve your goals without downcasting.
1) Don't manipulate a too broad type in the List. Additionally you could make IEvent a generic interface and generalize passPlayer() and passBlock() in pass() that you will move up in the interface.
The interface could look like :
public interface IEvent<T> {
void trigger();
void pass(T t);
}
And implementation of it could look like :
public class PlayerEvent implements IEvent<Player> {
private Player player;
public void trigger() {
// player does things
}
#Override
public void pass(Player t) {
}
}
Now with a more specific typed List you could write :
private Player player = ...;
public void executeEvents() {
List<IEvent<Player>> events = ...;
for (IEvent<Player> event : events) {
event.pass(player);
}
}
2) Use the visitor pattern to benefit from a double dispatch.
Event -> Visitor -> processing.
Each pass() method become a method of the Visitor.
You could enrich the IEvent interface to add an accept() method that accepts a Visitor :
public interface IEvent {
void trigger();
void accept(Visitor visitor);
}
Here the Visitor interface and implementation :
Visitor interface
public interface Visitor {
void visitBlockEvent(BlockEvent block);
void visitPlayerEvent(PlayerEvent player);
}
Visitor implementation
public class ProcessEventVisitor implements Visitor {
private Player player;
private Block block;
#Override
public void visitBlockEvent(BlockEvent blockEvent) {
// do your processing
}
#Override
public void visitPlayerEvent(PlayerEvent playerEvent) {
// do your processing
}
}
IEvent subclasses delegate now to the Visitor parameter the processing :
public class PlayerEvent implements IEvent{
public void trigger() {
// player does things
}
#Override
public void accept(Visitor visitor) {
visitor.visitPlayerEvent(this);
}
}
And the client code can now look like :
private Player player;
public void executeEvents() {
List<IEvent> events = ...;
ProcessEventVisitor visitor = new ProcessEventVisitor();
for (IEvent event : events) {
event.accept(visitor);
}
}
I'm trying to write an event engine in Java using the newly added lambdas. I would very much like it if the following code would work:
public class Test
{
public Test()
{
EventEngine.listen(EventType.THIS, self::thisEventCallback);
EventEngine.listen(EventType.THAT, self::thatEventCallback);
EventEngine.listen(EventType.OTHER, (other) -> other.doX());
}
private void thisEventCallback()
{
// do whatever here
}
private boolean thatEventCallback(SomeObject parameter)
{
return parameter.someCheckOrWhatever();
}
}
As far as I understand, I would have to define a generic empty interface, for example, public interface Listener {// nothing here}, and extend it via various other interfaces for each event type so I can specify different parameters and return types where necassary.
Obviously, that would require casting the callbacks to the specific interface inside the EventEngine's trigger method(s), but I have no problem with that.
However, before that I need to find out how to reference these private methods I have defined to the EventDispatcher.listen method. self::thisEventCallback doesn't work. Is there even a way to do this in Java 8 or is it only possible in Scala?
If not, then what would you suggest as a replacement that does not involve creating a new object for every listener/callback?
EventEngine.listen(EventType.THIS, this::thisEventCallback);
EventEngine.listen(EventType.THAT, this::thatEventCallback);
EventEngine.listen(EventType.OTHER, (other) -> other.doX());
So this instead of self.
And you need functional interfaces with one abstract method having the same signature as the callback.
public interface THISInterface {
public void thisEventCallback();
}
public interface THATInterface {
public boolean thatEventCallback(SomeObject parameter)
}
class EventEngine {
public void listen(Type t, THISInterfcace thisCallback) {
thisCallback.thisEventCallback();
}
public void listen(Type t, THATInterfcace thatCallback) {
boolean ok = thatCallback.thatEventCallback();
}
...
}
However there are already many functional interfaces predefined, which you should need to learn. For instance here, one would not need own interfaces.
class EventEngine {
public void listen(Type t, Consumer<Void> thisCallback) {
thisCallback.accept();
}
public void listen(Type t, Predicate<Void> thatCallback) {
boolean ok = thatCallback.test();
}
Whether the above is correct, I am not sure (at the moment deep in java 6 - sigh).
Instead of creating sub-interfaces adding new methods to a base interface you can define a conventional listener interface (like, say MouseListener) having multiple call-back methods and create sub-interfaces overriding all but one method with empty default methods for the sole purpose of allowing lambda implementations of the remaining single abstract method. They replace what classes like MouseAdapter did for previous Java versions (when using anonymous inner classes):
interface AllPurposeListener {// the only one our engine uses internally
void caseOne(int arg);
void caseTwo(String arg);
}
interface CaseOneListener extends AllPurposeListener {
#Override public default void caseTwo(String arg) {}
}
interface CaseTwoListener extends AllPurposeListener {
#Override public default void caseOne(int arg){}
}
// Of course, I over-simplify the engine’s listener registry here
AllPurposeListener listener;
public void listen(AllPurposeListener l) {
listener=l;
}
public void listen(CaseOneListener l) {
listener=l;
}
public void listen(CaseTwoListener l) {
listener=l;
}
private void foo(int i) { }
private void bar(String s) { }
void doRegistration() {
listen(this::foo);// register for case one
listen(this::bar);// register for case two
listen(new AllPurposeListener() { // for all cases
public void caseOne(int arg) {
}
public void caseTwo(String arg) {
}
});
}
I have a hierarchy of worker classes, all of which do some kind of processing to a workpiece. The idea is, that each worker does some pre processing, pushes the workpiece to the subclass and then does some postprocessing:
public void process(Workpiece wp) {
doPreprocessing(wp);
sub.process(wp); // this obviously doesn't work
doPostProcessing(wp);
}
Right now I'm solving this by declaring new abstract methods:
public final void process(Workpiece wp) {
doPreprocessing(wp);
subProcess(wp); // this obviously doesn't work
doPostProcessing(wp);
}
protected abstract void subProcess(Workpiece wp);
which has the obvious disadvantage that for each hierarchy-level, there is an additional, new method.
I would like to guarantee, that all pre- and post-process methods are executed even with new, user-implemented workers, which are not under my control.
How would you do that?
Following the template method pattern, you would do this by designing you class such that the doPreProcessing and doPostProcessing methods are overridden in subclasses. I'm guessing you don't want to do this, because you can't be sure the subclasses will call super, and thus you can't "guarantee that all pre- and post-process methods are executed even with new, user-implemented workers."
Instead of using inheritance, you could try a design that chains worker objects together, like this:
public abstract class Worker {
private Worker next;
protected Worker(Worker next) {
this.next = next;
}
public void process(Workpiece wp) {
preProcess(wp);
if (next != null)
next.process(wp);
postProcess(wp);
}
public abstract void preProcess(Workpiece wp);
public abstract void postProcess(Workpiece wp);
}
Your classes, and user-implemented classes, instead of extending the "next" worker, create the "next" worker in their constructors:
public class MyWorker extends Worker {
public MyWorker() {
super(new MyOtherWorker());
}
public abstract void preProcess(Workpiece wp) {
// code
}
public abstract void postProcess(Workpiece wp) {
// code
}
}
I'm trying to get around the ugly conditional casting involved when interpreting an update() call for an observable that will want to notify its observers of multiple types of events. Also, I'd prefer not to pass flags to the notifyObservers()/update() method.
I do not want the observers to have to poll the observable object to find out what's changed, I'd like this new data to be given to the observers via the update() method (or similar.)
I have an idea for a solution. I instanciate one observable object for each type of notification. For example: The observable is an object representing a hardware device, it will contain observables representing its state:
public final Observable connectionState = new Observable();
public final Observable dataState = new Observable ();
This way, observers don't need to do any sort of querying or conditional casting, as one observer, i.e. one overridden update() method can be used per notification type.
After much frustration this is the most elegant solution I can think of, however I have this horrible feeling that I've missed the point about how to use Observers/Observables properly.
My main issues with that solution are:
It still involves a cast (at least it's not conditional)
Since the observables need to be observable, they must be public members. While this does allow observers to call addObservable(), it also allows them to call notifyObservers().
Am I doing the right thing?
Thanks
You are struggling with the limitations of the Java 1.0 implementation of the Observer pattern. Take a look at this answer to the question Is java.util.Observable used anywhere?
They are not used, because their
design is flawed: they are not type
safe. You can attach any object that
implements Observer to any Observable,
which can result in subtle bugs down
the line.
Wrapping them inside a type safe
interface is about the same amount of
work as implementing the pattern from
scratch, so I guess the latter is
preferred in most cases.
Rather than trying to shoehorn your requirements into java.util.Observer, maybe you should just implement your own version of the pattern that better fits your needs.
You can try to use Observable paired together with Visitor pattern:
class MyObserver implements Observer, EventVisitor {
public void update(Observable o, Object arg) {
((EventAcceptor) arg).accept(this);
}
public void visit(SomeEvent v) {
System.out.println("SomeEvent: " + v.s);
}
public void visit(AnotherEvent v) {
System.out.println("AnotherEvent: " + v.info);
}
}
interface EventVisitor {
void visit(SomeEvent v);
void visit(AnotherEvent v);
}
interface EventAcceptor {
void accept(EventVisitor v);
}
class SomeEvent implements EventAcceptor {
public final String s;
public SomeEvent(String s) {
this.s = s;
}
public void accept(EventVisitor v) {
v.visit(this);
}
}
class AnotherEvent implements EventAcceptor {
public final String info;
public AnotherEvent(String info) {
this.info = info;
}
public void accept(EventVisitor v) {
v.visit(this);
}
}
class MyObservable extends Observable {
void handleSomeEvent() {
setChanged();
notifyObservers(new SomeEvent("some event"));
}
void handleAnotherEvent() {
setChanged();
notifyObservers(new AnotherEvent("some event"));
}
}
class Sample {
public static void main(String[] args) {
MyObservable observable = new MyObservable();
observable.addObserver(new MyObserver());
observable.handleSomeEvent();
observable.handleAnotherEvent();
}
}
There are lots of possible solutions for your problem. If you feel the Observable class isn't suited to your problem you can maintain your own collection of listeners.
interface Listener {
void onEvent1(Type1 arg);
void onEvent2(Type2 t2, Type3 t3);
void onEvent3();
}
List<Listener> listeners = new CopyOnWriteArray<Listener>();
public void addListener(Listener l) { listeners.add(l); }
public void onEvent1(Type1 arg) {
for(Listener l: listeners) l.onEvent1(arg);
}
I have the following (maybe common) problem and it absolutely puzzles me at the moment:
There are a couple of generated event objects which extends the abstract class Event and I want to divide them to Session Beans, like
public void divideEvent(Event event) {
if (event instanceof DocumentEvent) {
documentGenerator.gerenateDocument(event);
} else if (event instanceof MailEvent) {
deliveryManager.deliverMail(event);
...
}
...
}
But there could be more than two event types in future, so the if-else will be long and maybe unreadable. Additionally I think instanceof is not really "best practice" in this case.
I could add an abstract method to the Event type and have them divide itself but then I have to inject the specific Session Beans within each entity.
Is there any hint to achieve a "pretty" solution for this problem?
Thanks for any help!
The simplest approach is to have the Event provide a method you can call so the Event knows what to do.
interface Event {
public void onEvent(Context context);
}
class DocumentEvent implements Event {
public void onEvent(Context context) {
context.getDocumentGenerator().gerenateDocument(this);
}
}
class MailEvent implements Event {
public void onEvent(Context context) {
context.getDeliveryManager().deliverMail(event);
}
}
class Context {
public void divideEvent(Event event) {
event.onEvent(this);
}
}
Polymorphism is your friend.
class DocumentGenerator {
public void generate(DocumentEvent ev){}
public void generate(MainEvent ev){}
//... and so on
}
Then just
DocumentGenerator dg = new DocumentGenerator();
// ....
dg.generate(event);
Update
A number of people have raised the objection that you "have to know the kinds of event at compile time." And, yes, you clearly have to know what events you're interpreting at compile time of the generator part, when else would you be able to write the generating part?
These competing examples use Command pattern, which is fine, but means Events have to know the details not just of their representation but of how to print their representation. That means each class may have two kinds of requirements changes to which their sensitive: changes in what events represent, and changes in the way the events are represented in print.
Now, consider, for example, needing to internationalize this. In the Command-pattern case, you have to go to n classes for n different Event types and write new do methods. In the polymorphism case, the changes are localized to one class.
Naturally if you need to internationalize once, you may need many languages, which drive you to adding something like a Strategy to each class in the Command-pattern case, requiring now n classes × m languages; again, you need only have one strategy and one class in the polymorphism case.
There are reasons to choose either approach, but to claim the polymorphism approach is wrong is just incorrect.
Each event has a function, say do.
Each subclass overrides do, to do (:P) the appropriate action.
Dynamic dispatch does everything else afterwards.
All you need to do, is call event.do()
I have no commenting rights and i dont know the exact answer. But is it just me or some ppl here suggest using overloading (which happens at compile time and therefore just generate compile error) to solve this problem?
Just an example. As you see, it will not compile.
package com.stackoverflow;
public class Test {
static abstract class Event {}
static class MailEvent extends Event {}
static class DocEvent extends Event {}
static class Dispatcher {
void dispatchEvent(DocEvent e) {
System.out.println("A");
}
void dispatchEvent(MailEvent e) {
System.out.println("B");
}
}
public static void main(String[] args) {
Dispatcher d = new Dispatcher();
Event e = new DocEvent();
d.dispatchEvent(e);
}
What's the problem with exploiting the method resolution order?
public void dispatchEvent(DocumentEvent e) {
documentGenerator.gerenateDocument(event);
}
public void dispatchEvent(MailEvent e) {
deliveryManager.deliverMail(event);
}
Let Java do the work of matching the correct argument type, then just dispatch the event properly.
This is a typical use case for Sum types, also known as tagged unions. Unfortunately, Java does not support them directly, so they have to be implemented using some variation of the visitor pattern.
interface DocumentEvent {
// stuff specific to document event
}
interface MailEvent {
// stuff specific to mail event
}
interface EventVisitor {
void visitDocumentEvent(DocumentEvent event);
void visitMailEvent(MailEvent event);
}
class EventDivider implements EventVisitor {
#Override
void visitDocumentEvent(DocumentEvent event) {
documentGenerator.gerenateDocument(event);
}
#Override
void visitMailEvent(MailEvent event) {
deliveryManager.deliverMail(event);
}
}
Here we have defined our EventDivider, now to provide a dispatch mechanism:
interface Event {
void accept(EventVisitor visitor);
}
class DocumentEventImpl implements Event {
#Override
void accept(EventVisitor visitor) {
visitor.visitDocumentEvent(new DocumentEvent(){
// concrete document event stuff
});
}
}
class MailEventImpl implements Event { ... }
public void divideEvent(Event event) {
event.accept(new EventDivider());
}
Here I used maximum possible separation of concerns so that responsibility of each class and interface is one and only one. In real life projects DocumentEventImpl, DocumentEvent implementation and DocumentEvent interface declaration are usually merged into a single class DocumentEvent, but that introduces circular dependencies and forces some dependencies between concrete classes (and as we know, one should prefer to depend on interfaces).
Additionally, void should usually be replaced with a type parameter to represent the result type, like this:
interface EventVisitor<R> {
R visitDocumentEvent(DocumentEvent event);
...
}
interface Event {
<R> R accept(EventVisitor<R> visitor);
}
This allows one to use stateless visitors, which are very nice to deal with.
This technique allows to (almost?) always eliminate instanceof mechanically rather than having to figure out a problem-specific solution.
You could register each of your handler classes against each event type, and perform dispatch when event happens like this.
class EventRegister {
private Map<Event, List<EventListener>> listerMap;
public void addListener(Event event, EventListener listener) {
// ... add it to the map (that is, for that event, get the list and add this listener to it
}
public void dispatch(Event event) {
List<EventListener> listeners = map.get(event);
if (listeners == null || listeners.size() == 0) return;
for (EventListener l : listeners) {
l.onEvent(event); // better to put in a try-catch
}
}
}
interface EventListener {
void onEvent(Event e);
}
And then get your specific handlers to implement the interface, and register those handlers with the EventRegister.
You could have a Dispatcher interface, defined like
interface Dispatcher {
void doDispatch(Event e);
}
with implementations like DocEventDispatcher, MailEventDispatcher, etc.
Then define a Map<Class<? extends Event>, Dispatcher>, with entries like (DocEvent, new DocEventDispatcher()). Then your dispatch method could be reduced to:
public void divideEvent(Event event) {
dispatcherMap.get(event.getClass()).doDispatch(event);
}
Here's a unit test:
public class EventDispatcher {
interface Dispatcher<T extends Event> {
void doDispatch(T e);
}
static class DocEventDispatcher implements Dispatcher<DocEvent> {
#Override
public void doDispatch(DocEvent e) {
}
}
static class MailEventDispatcher implements Dispatcher<MailEvent> {
#Override
public void doDispatch(MailEvent e) {
}
}
interface Event {
}
static class DocEvent implements Event {
}
static class MailEvent implements Event {
}
#Test
public void testDispatcherMap() {
Map<Class<? extends Event>, Dispatcher<? extends Event>> map = new HashMap<Class<? extends Event>, Dispatcher<? extends Event>>();
map.put(DocEvent.class, new DocEventDispatcher());
map.put(MailEvent.class, new MailEventDispatcher());
assertNotNull(map.get(new MailEvent().getClass()));
}
}