Sud's Blog
The Observer Pattern in Practice
I needed a way to display the current state of a long running job to the user. You'll agree that being able to see the progress bar move and having constant feedback from the application as opposed to having the application lock up for several minutes while it crunches away makes the user experience infinitely better. The Observer pattern to the rescue. If you aren't familiar with this pattern, I recommend a brief de-tour before coming back here. Also, I use Java and it's support for the Observer pattern though you should be able to implement it in C# or other similar languages.
Here is the application architecture:
UI Layer
Business Layer
Persistence Layer
Nothing special, just your traditional layered architecture. Except that the long running operation encompasses processing in the business layer and the persistence layer. So at the UI layer (ViewModel.java) I instantiate an Observable LogData object. This object must be accessible in all the layers. Consequently LogData.java needs to be located in a common package that all the other layers can depend on.
Here is the Observable LogData.java.
public class LogData extends java.util.Observable {
private List<String> messages = new ArrayList<String>();
public List<String> getMessages() {
return messages;
}
public void add(String message) {
messages.add(message);
setChanged();
notifyObservers(message);
}
public void clear() {
messages.clear();
}
}
LogData wraps a List object that tracks all logged messages. When a calling class adds a message via the add() method, the notifyObservers() method is fired.
Here is the UI model class ViewModel.java which serves as the Observer.
public final class ViewModel implements java.util.Observer {
public void processButtonClick() {
LogData logData = new LogData();
logData.addObserver(this);
Backend backend = new Backend(logData);
backend.process(); // make call to business layer
}
/*
* (non-Javadoc)
*
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
public void update(Observable o, Object arg) {
message = (String) arg;
System.out.println(message);
}
}
The processButtonClick() method is called upon a mouse click in the UI (not shown here). A LogData object is instantiated and the viewModel is added to it as an observer via the addObserver() method call. This hooks the Observable logData and the Observer viewModel together. Changes to the logData object will fire the update() method in viewModel.
Backend.java is the business logic code where we make use of the logData object to log the feedback.
public class Backend {
private LogData logData;
public Backend(LogData logData) {
this.logData = logData;
}
public void process() {
.....
.....
logData.add("Completed");
}
}
Tying it all together, when the process() method in Backend calls logData.add(message), the logData.add() method fires the notifyObservers(message), which in turn fires the update() method in ViewModel.
This is a simplified version of the solution and the goal was to help you see how the observer pattern can be used.
Please add comments on better or different ways to achieve the same ends.
Posted at 03:45PM Apr 15, 2008 by sudhakar in Java | Comments[0]
Pesky "Access Restriction" issue in Eclipse 3.2
If you are developing plugins using Eclipse PDE, here's an issue you might run into in Eclipse 3.2 (haven't confirmed on 3.3.x yet) when referencing classes in plugins listed in the dependencies tab of MANIFEST.MF
"Access restriction: The type XXXXXXXX is not accessible due to restriction on required project XXXXXXXXXXXXXXXXXXXX"
This is resolved by re-ordering the plugins in the dependencies tab till the compilation error disappears. I haven't been able to find much information about what causes this issue in the first place and why this solution works. But it works and sometimes that's sufficient for me!
Posted at 02:41PM Mar 31, 2008 by sudhakar in Java | Comments[0]