What is be the best choice to register an observer? I did not find anything on this subject. Mostly "push vs. pull" is discussed, but there are also a couple of options to register an observer.
public static void main(String[] args)
{
Subject subject = new ConcreteSubject();
// External registration
Observer observerExternal = new ConcreteObserverExternal();
subject.registerObserver(observerExternal);
// Internal registration, option 1
Observer observerInternal1 = new ConcreteObserverInternal1(subject);
// Internal registration, option 2
ConcreteObserverInternal2 observerInternal2 = new ConcreteObserverInternal2(subject);
}
interface Observer
{
void inform();
}
class ConcreteObserverExternal implements Observer
{
#Override
public void inform()
{
// do sth.
}
}
class ConcreteObserverInternal1 implements Observer
{
public ConcreteObserverInternal1(Subject subject)
{
subject.registerObserver(this);
}
#Override
public void inform()
{
// do sth.
}
}
class ConcreteObserverInternal2
{
public ConcreteObserverInternal2(Subject subject)
{
subject.registerObserver(() -> inform());
}
private void inform()
{
// do sth.
}
}
interface Subject
{
void registerObserver(Observer obs);
void unregisterObserver(Observer obs);
}
class ConcreteSubject implements Subject
{
#Override
public void registerObserver(Observer obs)
{
// register
}
#Override
public void unregisterObserver(Observer obs)
{
// unregister
}
private void foo()
{
// ...
notifyObservers();
}
private void notifyObservers()
{
// notify observers
}
}
Here are three cases I have in my code:
An observer is registered at program start and is never unregistered. In this case, all of the 3 options would be possible.
An observer is registered somewhere and needs to be unregistered when some external event occurs. The observer does not know about this external event and obviously it must be registered externally (option 1).
An observer is registered somewhere and needs to be unregistered when some external event occurs. The observer knows what happened, because it is also an observer of this external event. In this case, all of the 3 options would be possible.
In the cases where all 3 options are possible, which one is the best from an OO and clean-code point of view?
Here is a list of some pros and cons I think each option has.
1. External registration
Pros:
- Less parameters in the constructor of the observer.
- Subject does not need to be abstracted to promote loose coupling between Subject and Observer.
Cons:
- One must not forget to register the observer in the client code.
- Client code is responsible for registration.
Neutral:
- The observer has an additional public method.
- Observer can be registered / unregistered by client code.
2. Internal registration, option 1: Concrete observer implements the Observer interface
Pros:
- Observer is responsible for registration.
- Registration cannot be forgotten, because one is forced to pass the Subject to the Observer's constructor.
Cons:
- One more parameter in the constructor of the observer.
Neutral:
- The observer has an additional public method.
- Observer can be registered / unregistered by client code.
- Observer can register / unregister itself.
3. Internal registration, option 2: Concrete observer does NOT implement the Observer interface
Pros:
- Observer is responsible for registration.
- Registration cannot be forgotten, because one is forced to pass the Subject to the Observer's constructor.
- Observer does not have an additional public method that could be abused by anything not related to "Subject notifying Observer".
Cons:
- One more parameter in the constructor of the observer.
Neutral:
- Observer can only register / unregister itself.
Given the subtle differences you raised between 'external' and 'internal' registrations, it looks like there won't be one right answer. Still, I'll try.
I'd prefer 'external' registration to other two for two reasons:
The Observers don't know anything about the Subjects; i.e., they are fairly decoupled. For e.g., I can attach one Observer to multiple Subjects, and no one would have to change.
More in line with the Single Responsibility principle. The Observer only cares about what it needs to do when informed. It doesn't care about registering/unregistering with anyone.
Related
I have to wait till the HashMap key's value change from another thread and have to continue the request processing after that.
I think the most flexible solution will be to implement the Observer pattern.
Note that build-inn interfaces Observer and Observable are deprecated since JDK version 9. Even if you are using Java 8 don't use them. The problem with them is that their names as well as the method name update() of the Observer don't tell anything to the reader of the code about the event that was triggered and what kind of actions might follow.
Ass you can see from the diagram, the subject should contain a collection of observers (or listeners).
The subject in your case should be class contains a HashMap updates of which you want to listen. Don't extend the map, wrap it with your class instead. Because if you choose to extend HashMap your code will become dependent on its implementation. And any changes in the HashMap, for instance, new methods were added or existing were improved could break your code (this topic is covered in the book "Effective Java" by Joshua Blochtake, have a look at it for more information).
So let's say we have a class OrderManager that maintains a map of Orders. This class will be a subject.
A couple of services like BillingManager, LoggingManagerand maybe some more needs to notified new order was added. These are our ***observers***. All these classes an interface, let's sayOrderAddedListenerthat defines a single methodonOrderAdded(Order order)`, that's the event we are interested in.
Note, if you need to listen to other events like removal or update, you need to define a new interface with a method responsible for that for every target event as the Interface segregation principle suggests.
OrderManager has to have a collection of observers. When a new order is being added, subject iterates through the collection of observers and invokes onOrderAdded() method on each of them.
In order to add an observer that need to listen to the order-added event OrderManager has to define a method to register it, and it's also good practice to add another one to unregister the observer that has registered to be able to remove it when you no longer need it.
Asynchronous processing
Note, that in this example, events are being processing in the same thread. If actions performed by observers are costful or might block the thread, in order to fire them asynchronously you can create a class that will implement Runnable and hold references to the observer and event (order the was added/updated), and method run() will trigger the observer. And when a new event occurs, OrderManager instead of invoking onOrderAdded() on each observer should create a new instance of that class implementing runnable by passing an observer and a new order to its constructor and then create and fire a new thread.
It's a simplified approach. But I guess it'll give an understanding of the general idea.
Implementation example
That how it might look like:
public class OrderManager {
private Map<Long, Order> orderById = new HashMap<>();
private Set<OrderAddedListener> listeners = new HashSet<>();
public void addOrder(Order order) {
// notifying observers
listeners.forEach(observer -> observer.onOrderAdded(order));
orderById.put(order.getId(), order);
}
// more methods like removeOrder(), getOrderCount() etc.
public boolean registerOrderAddedListener(OrderAddedListener listener) {
return listeners.add(listener);
}
public boolean unregisterOrderAddedListener(OrderAddedListener listener) {
return listeners.remove(listener);
}
}
public interface OrderAddedListener {
void onOrderAdded(Order order);
}
public class LoggingManager implements OrderAddedListener {
private Logger logger;
#Override
public void onOrderAdded(Order order) {
// logger.log();
System.out.println("Log message has been written");
}
}
public class BillingManager implements OrderAddedListener {
private BillingService billingService;
#Override
public void onOrderAdded(Order order) {
// billingService.sendBill(order);
System.out.println("A bill has been sent");
}
}
main() - a simple demo
public static void main(String[] args) {
OrderManager orderManager = new OrderManager();
orderManager.registerOrderAddedListener(new LoggingManager());
orderManager.registerOrderAddedListener(new BillingManager());
orderManager.addOrder(new Order());
}
Output
A log message has been written
A bill has been sent
I am trying to use the MVC design pattern to observe objects within the model class. for example the model class represents a building which has x number of floors and each floor has a door, how would you observer the door which is inside the floor object. How would the view objects reach the door object to register themselves as observers?
Maybe what you want is the Observer Pattern:
The pattern has an observer object that listens for events and notify all listeners when that event occurs. You can made your building a observer and check for modifications in the doors, when something changes you can notify all the listeners. Now your building is a observer the views can register as a listener.
Here is a simple code example:
Here is the building class that acts as a observer:
class Building {
List<Observers> listeners = new ArrayList<>();
public void checkDoors(){
//check for variations...
if(variation) notifyListeners(); //iterate over all observers and notify them
}
public void addListener(Listener listener){
listeners.add(listener);
}
}
And here is the view that listens for notifications on doors:
class View implements Listener {
public View(Building building){
building.addListener(this);
}
void handleDoor(Door door){
//do some stuff...
}
}
I have a problem with Observer pattern.
First, I have a HttpHelper class to get data from server, I used it as Observerable.
public class HttpHelper extends Observable,Runnable{
public void run(){
//do long task to get data
String result = getData();
setChanged();
notifyObservers(result);
}
}
The DataManager class get data from HttpHerlper when completed, then do some business task.
public class DataManager implements Observer {
public void doTask(){
HttpHelper helper = new HttpHelper();
helper.addObserver(this);
Thread thread = new Thread(helper);
thread.start();
}
public void update(Observable obj, Object data) {
if (data instanceof String) {
// do some stuff with this data
// Then I want to notify the result to the view
Model model = doSomething(data);
notify(model)
}
}
}
Finaaly, View class will update data when DataManager complete task.
public class View{
private void getData(){
DataManager manager = new DataManager()
manager.doTask();
}
public void update(Observable obj, Object data) {
}
}
Should I use Observer again? And how can I do that?
P/s: for some reason, HttpHelper and DataManager must be separated.
Update: Here is the class structure
https://www.dropbox.com/s/givn6vzvqr4cgye/bkd.png
IMO, the relationship between HttpHelper and DataManager doesn't need an observer pattern. It seems to be just a callback to notify the manager that the processing is done. Observers are better suited for dispatching events to multiple, different listeners via a common interface, not to a single listener. Having said that, what you have will work. Check this article on implementing callbacks if you want to follow my advice
Now, for the relationship between the manager and the view i do agree that you should use an observer pattern, this will allow you to create different views that react differently to the same events. This means that it's DataManager that should extend Observable, and every view listening it should implement Observer
Finally, i have to say that if you plan on having different types of events, the JDK observable and observer (java.util) mechanism is not very clean. My biggest criticism is that the second argument of update is an Object, so you end up with a huge list of if else where you need to check instanceof like in your example, which in general is not good practice. An alternative is to use the event notification mechanism from the UI classes (like EventObject and EventListener) , they are part of the UI classes but are really more generic than just UIs. see this other question
Oh and if you can, try to avoid cascading events. It makes code hard to read and debug. Maybe the view could observe directly the HttpHelper??
I think you can make the View an Observable but that chain of Observation may make your code complex.
The immediate solution came to me is:
Make an Observer controller
class Controller implements Observer{
DataManager dm;
View v;
void update(...){
Data d = dm.getData();
v.loadData(d);
}
}
and make your Controller observe HttpHelper.
I'm implementing a client-server system where the client is in a continuous blocking read loop listening for messages from the server. When a message is received I'd like to raise an "event" based on the type of the message, which other GUI classes may add listeners to. I'm more familiar with C# events so I am still getting used to the Java way of doing things.
There will be many message types so I will need an interface for each, call it MessageTypeAListener, MessageTypeBListener, etc., each of which will contain one handle method, which my GUI classes will implement. However, there will be be many types and instead of maintaining a list of listeners per type and having several "fire" methods I wanted to have one big listener list and a typed fire method. Then the fire method could say "only fire listeners whose type is what I specify."
So for example (pseudocode):
ListenerList.Add(MessageTypeAListener);
ListenerList.Add(MessageTypeBListener);
<T> fire(message) {
ListenerList.Where(type is T).handle(message)
}
...
fire<MessageTypeAListener>(message);
However, type erasure seems to be making this difficult. I could try casting and catching exceptions but that seems wrong. Is there a clean way of implementing this or is it just wiser to keep a separate list of listeners for every type, even though there will be tons of types?
I implemented something like this, cause I have a visceral dislike of Java's EventListenerList. First, you implement a generic Listener. I defined the listener based upon the Event it was receiving, with basically one method
interface GenericListener<T extends Event> {
public void handle(T t);
}
This saves you having to define ListenerA, ListernerB etc... Though you could do it your way with ListenerA, ListenerB, etc, all extending some base like MyListener. Both ways have plusses and minuses.
I then used a CopyOnWriteArraySet to hold all these listeners. A set is something to consider cause all too often listeners get added twice by sloppy coders. YMMV. But, effectively you have a Collection<GenericListener<T extends Event>> or a Collection<MyListener>
Now, as you've discovered, with type erasure, the Collection can only hold one type of listener. That is often a problem. Solution: Use a Map.
Since I'm basing everything upon the event, I used
Map<Class<T extends Event>, Collection<GenericListener<T extends Event>>>
based upon the class of the event, get the list of listeners who want to get that event.
Your alternative is to base it upon the class of the listener
Map<Class<T extends MyListener>, Collection<MyListener>>
There's probably some typos above...
Old-fashioned pattern approach, using Visitor pattern:
class EventA {
void accept(Visitor visitor) {
System.out.println("EventA");
}
}
class EventB {
void accept(Visitor visitor) {
System.out.println("EventB");
}
}
interface Visitor {
void visit(EventA e);
void visit(EventB e);
}
class VisitorImpl implements Visitor {
public void visit(EventA e) {
e.accept(this);
}
public void visit(EventB e) {
e.accept(this);
}
}
public class Main {
public static void main(String[] args) {
Visitor visitor = new VisitorImpl();
visitor.visit(new EventA());
}
}
More modern approach is just to have Map between classes of events, which should not derive each other, and respective handlers of these events. This way you avoid disadvantages of Visitor pattern (which is, you'll need to change all your visitor classes, at least, base of them, every time you add new Event).
And another way is to use Composite pattern:
interface Listener {
void handleEventA();
void handleEventB();
}
class ListenerOne implements Listener {
public void handleEventA() {
System.out.println("eventA");
}
public void handleEventB() {
// do nothing
}
}
class CompositeListener implements Listener {
private final CopyOnWriteArrayList<Listener> listeners = new CopyOnWriteArrayList<Listener>();
void addListener(Listener l) {
if (this != l)
listeners.add(l);
}
public void handleEventA() {
for (Listener l : listeners)
l.handleEventA();
}
public void handleEventB() {
for (Listener l : listeners)
l.handleEventB();
}
}
After going through iterations of just about everyone's suggestions here, I ended up going a very slightly modified route of the standard Listener interfaces and listener lists. I started with Swing's EventListenerList, only to be disappointed with the amount of add/remove methods for dozens of message types. I realized this could not be condensed while still maintaining a single EventListenerList, so I started thinking about a separate list for each type. This makes it similar to .NET events where each event holds its own list of delegates to fire when raised. I wanted to avoid tons of add/remove methods, so I made a quick Event class that just looks like this:
public class Event<T extends EventListener> {
private List<T> listeners = new ArrayList<T>();
public void addListener(T listener) {
listeners.add(listener);
}
public void removeListener(T listener) {
listeners.remove(listener);
}
public List<T> getListeners() {
return listeners;
}
}
Then I keep several instances of this class around, each typed according to a listener, so Event<MessageTypeAListener>, etc. My classes can then call the add method to add themselves to that particular event. I would've like to be able to call a generic Raise method on the Event instance to then fire all the handlers, but I did not want them to all have to have the same "handle" method, so this was not possible. Instead, when I'm ready to fire the listeners, I just do
for (MessageTypeAListener listener : messageTypeAEvent.getListeners())
listener.onMessageTypeA(value);
I'm sure this is not a new idea and has probably been done before and in better/more robust ways, but it's working great for me and I'm happy with it. Best of all, it's simple.
Thanks for all the help.
If you only have simple events, i.e. events without data or where all events have the same data types, enum could be a way forward:
public enum Event {
A,
B,
C
}
public interface EventListener {
void handle(Event event);
}
public class EventListenerImpl implements EventListener {
#Override
public void handle(Event event) {
switch(event) {
case A:
// ...
break;
}
}
}
public class EventRegistry {
private final Map<Event, Set<EventListener>> listenerMap;
public EventRegistry() {
listenerMap = new HashMap<Event, Set<EventListener>>();
for (Event event : Event.values()) {
listenerMap.put(event, new HashSet<EventListener>());
}
}
public void registerEventListener(EventListener listener, Event event) {
Set<EventListener> listeners = listenerMap.get(event);
listeners.add(listener);
}
public void fire(Event event) {
Set<EventListener> listeners = listenerMap.get(event);
for (EventListener listener : listeners) {
listener.handle(event);
}
}
}
Comments:
The switch statement in the EventListnerImpl may be omitted if it is only registered to a single event, or if it should always act in the same way regardless of which Event it receives.
The EventRegister has stored the EventListener(s) in a map, meaning that each listener will only get the kind of Event(s) that it has subscribed to. Additionally, the EventRegister uses Sets, meaning that an EventListener will only receive the event at most once (to prevent that the listener will receive two events if someone accidentally registers the listener twice).
I'm starting with GWT and learning Event bus concepts now. I find this solution extremely complicated. So I tried to simplify it by writing prototype by myself to see all problems.
At first I will write about my understanding of event bus (that can be completely wrong).
We have events like this
public class FooEvent extends GwtEvent<FooHandler> {
public static Type<FooHandler> TYPE = new Type<FooHandler>(); //as event type integer ID
//for.. hm.. probably some inner use in Event Bus
#Override public Type<FooHandler> getAssociatedType() {
return TYPE;
}
//for handling
#Override protected void dispatch(FooHandler handler) {
handler.someMethod(this);
}
}
handler interface,
public interface FooHandler extends EventHandler {
void someMethod(FooEvent event);
}
usage
eventBus.addHandler(FooEvent.TYPE, new FooHandler() {
#Override
public void someMethod(FooEvent event) {
//bla-bla
}
});
eventBus.fireEvent(new FooEvent());
Thats it. And now my prototype.
//replaced GwtEvent
interface UniGwtEvent {
}
//than, event pretty simple
public class FooEvent extends UniGwtEvent {
}
//replaced GwtEventHandler. You should not create special handler class per event!
public interface UniEventHandler<T extends UniGwtEvent> {
void handle(T event);
}
//event bus prototype(in pseudocode)
class UniEventBus {
//map. keys getted from class. as I understand, it's possible from GWT 1.5 see http://code.google.com/p/google-web-toolkit/issues/detail?id=370
public <T extends UniGwtEvent> void addListener(Class<T> event, UniEventHandler<T> handler){
map.put(event.getName(), handler);
}
public void fireEvent(UniGwtEvent event){
if(map.contains(event.getClass().getName())){
map.get(event).handle(event);
}
}
}
usage
eventBus.addListener(FooEvent.class, new UniEventHandler<FooEvent>(){
#Override
public void handle(FooEvent event) {
bla-bla
}
});
eventBus.fireEvent(new FooEvent());
I think this solution is much better since you shouldn't make unnecessary Type manipulation and create Handler Class per event. I see only one disadvantage - you should specify generic type on handler creation. But I suppose there are many other disadvantages or ever issues that makes this solution impossible. What are they?
There is no obvious advantage to using your implementation. As I read it there are two differences between yours and GWT's EventBus:
Using Strings instead of Type objects to bind event handlers to event types. This is not a meaningful difference - there's no penalty to having more types in your application and I suspect that, at runtime, Strings will use slightly more resources than Types.
Dispatching events to the appropriate handlers directly instead of delegating to the event type. I prefer GWT's approach here because it affords flexibility in how events are dispatched. One might, for example, want handlers to implement two different methods that are invoked depending on the context of the event. Take the following (trivial) example:
public class ExampleEvent extends GwtEvent<ExampleEvent.Handler> {
public interface Handler extends EventHandler {
void onExample(Integer id);
void onExample(String name);
}
private final Integer id;
private final String name;
public ExampleEvent(Integer id) {
this.id = id;
this.name = null;
}
public ExampleEvent(String name) {
this.name = name;
this.id = null;
}
public void dispatch(Handler handler) {
if (name != null) {
handler.onExample(name);
} else {
handler.onExample(id);
}
}
}
In this case delegating dispatch to the event allows us to take an action that must be performed for every handler (determining whether the event contains an id or a name) without requiring that the test be performed in every individual event handler.
I recommend using GWT's EventBus implementation - it works and it is tested.
There are other event bus implementations out there that will do a good job. I recently created a very efficient event bus (Mbassador) that I have been using in production for a while now. It's hosted on github and you are invited to take a look.
https://github.com/bennidi/mbassador
Another option would be to use google guavas event bus but it lacks some useful features (which is why I implemented my own solution)
EDIT: I created a performance and feature comparison for a selection of available event bus implementations including Guava, MBassador and some more. The results are quite interesting. Check it out here
http://codeblock.engio.net/?p=37