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...
}
}
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 have a simple Controller object that that implements Observer (i.e. it is the observer) which listens for events from a Mouse object that extends Observable (i.e. it is the observee).
So there can be multiple events in a Mouse object e.g. left click, scroll up, etc.
Now the Controller class implements the required method which is called every time any of the above events happen:
#Override
public void update(Observable o, Object arg)
{
// Handle mouse event
}
So it is the arg parameter that I am having trouble deciding how to approach (this case I am working on is simple enough such that the o parameter is not a concern). What is a good way to distinguish between different mouse events without using typeof?
I.e. what parameter should I feed in the notifyObservers(Object arg) method in the Mouse observee class?
Reading the comments it seems that you are using SWT -- SWT already implements event handlers via observer/observable callbacks.
What you are trying to do here is implement another layer of observer pattern on top of the already implemented observer pattern by SWT, which doesn't make much sense. But if you really wanted to do it for practice you might want to make several inner private classes to handle different events, e.g:
/**
* Controller.java
*/
import java.util.Observable;
import java.util.Observer;
public class Controller
{
/**
* The controller's inner classes are to be notified of mouse events.
*/
public Controller(Mouse mouse)
{
mouse.addObserver(new LeftClickObserver());
mouse.addObserver(new ScrollUpObserver());
}
private class LeftClickObserver implements Observer
{
#Override
public void update(Observable o, Object arg)
{
// TODO Handle left clicks
}
// Other left click logic here
// ...
}
private class ScrollUpObserver implements Observer
{
#Override
public void update(Observable o, Object arg)
{
// TODO Handle scroll up
}
// Other scroll up logic here
// ...
}
}
Then you can call the notifyObservers(Object arg) method in the appropriate event in the Mouse class to trigger a callback to the Controller.
However as mentioned, you should instead make use of the existing SWT libraries to handle events, then separate the implementation of the event handling in the controller, and away from the view (as you are trying to do already). Here's a simple example of how to do that (assuming you have a Controller initialized somewhere in the Mouse class, and the appropriate methods in the Controller class):
final Button button = new Button(shell, SWT.PUSH);
button.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent event) {
controller.handleWidgetSelectedEvent(event); // controller decides what to do...
}
public void widgetDefaultSelected(SelectionEvent event) {
controller.handleWidgetDefaultSelectedEvent(event); // controller decides what to do...
}
});
Note that there are some versions of the MVC pattern where the View does much of the handling of the events, and/or the model; so really, it depends on your project. Probably handling the event at the view straight away is the easiest strategy.
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.
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.
Passengers and Taxis run independently in different threads. After great help of Edwin Buck here I used MVC for Taxi management. In my situation both view(JTaxiPanel) and models(Passenger) listen to Taxi. When Taxi fires event(for example when passenger is added or taxi start driving...) all listeners are notified. The problem is that Passenger will be notified even if other passengers are added to taxi. I want passenger to listen, but I don't think that Passenger should be notified when other passengers are added or in some other situations.
How to handle this kind of problem?
Should taxi have 2 list of listeners or there is some other way to do it?
class Station extends Thread
{
LinkedList<Taxi> taxisInQueue;
LinkedList<Passenger> passengersInQueue;
void matchPassengerToTaxi()
{
Taxi taxi = taxisInQueue.removeFirst();
Passenger passenger = passengersInQueue.removeFirst();
// passenger listen to taxi
taxi.addListener(passenger);
taxi.addPassenger(passenger);
}
}
class Passenger extends Thread implements TaxiListener
{
#Override
public void taxiChanged(TaxiEvent event)
{
}
}
class Taxi extends Thread
{
Vector<Passenger> passengers;
public void addPassenger(Passenger passenger)
{
passengers.add(passenger);
// notify listeneres
fireEvent(new PassengerAddedEvent(this, passenger));
}
}
class JTaxiPanel extends JPanel implements TaxiListener
{
public JTaxi(Taxi model)
{
this.model = model
// view listens to Taxi
model.addTaxiListener(this);
}
#Override
public void taxiChanged(TaxiEvent event)
{
}
}
To generalize what you are saying: event/listener is a broadcast communication pattern. If you build a system where many listeners are ignoring most broadcasts, you are asking for performance problems and adding complexity in the listeners.
To fix this, choose different communication channels implemented as different event and listener types for different kinds of communication. In this case, rather than a single event type that means "something happened to the taxi", find different classes of events that happen to a taxi and that have smaller listener sets.
A rule of thumb is that the most frequently occurring events should have the smallest number of listeners ignoring them.
Another rule of thumb is to make these different types of events mutually exclusive. You don't want a case where the same entity is notified twice of the same event.
Another approach frequently used in GUI systems is an event mask. When a listener is installed, a mask of desired event types is included. This lets the sender (in this case the Taxi) avoid sending to a listener that isn't interested.
You can check in your passenger listener if the passenger which has been added is the same as this. Comparing ids or some other equality criteria. If they are not the same, they don't do anything...