Hi all,
I'm encountering a bit of a design conundrum. I can think of two solutions for my problem, and I'm not sure which is better for my particular situation.
Essentially, the problem is how to propagate events from the controllers to the UI. I've got a class called Client which represents, you guessed it, a Client! The Client class contains references to ServerManager and CacheManager -- two classes which manage the server interaction and caching operations.
The problem is that the ServerManager may receive notifications from the Server asynchronously which require action on the UI. It seems to me the first potential solution is to have the UI add a listener to the ServerManager directly:
I personally don't like this at all... my instinct is that only the Client should be interacting with it's ServerManager. In order to make that the case I have to propogate the "onServerNotification" event from the ServerManager to the Client and THEN to the UI:
This seems a lot cleaner to me, however, in order to do this, I need the ServerManager to tell its parent Client object to issue the notification it just received:
In ServerManager:
This part I don't like. Because this required that Client have a public method which loops through the list of listeners and issues the callback to each one. I don't think such a method should be public. That exposes behaviour to other parts of the application which have no business accessing it (random parts of the app should not be able to trick the Client into thinking it received a server notifiction).
SO that leaves me adding a protected Listener to the Client which listens to its own ServerManager for onReceivedNotification events. The UI then adds an ServerNotificationListener to the Client, and when the Client receives the event from it's ServerManager, it passes it along to the UI:
ServerManager:
Client:
Finally, from the UI layer...
MainActivity:
So that's where I'm at now. I like the current implementation for its encapsulation. It seems clean to me. However, it also seems like it might be overly convoluted...
I'm sure this is a common problem, and I'd like to find the best solution possible -- if anyone out there has a better way, or can think of a good reason why this is TOO convoluted, I'd appreciate your comments.
Cheers!
PS. I typed all that code directly into the browser, so if there are any errors, or you can't tell what it's meant to do, please ask. The intention of the code is what matters here.
I'm encountering a bit of a design conundrum. I can think of two solutions for my problem, and I'm not sure which is better for my particular situation.
Essentially, the problem is how to propagate events from the controllers to the UI. I've got a class called Client which represents, you guessed it, a Client! The Client class contains references to ServerManager and CacheManager -- two classes which manage the server interaction and caching operations.
The problem is that the ServerManager may receive notifications from the Server asynchronously which require action on the UI. It seems to me the first potential solution is to have the UI add a listener to the ServerManager directly:
Code:
Client c = new Client();
c.getServerManager().addListener(new ServerManager.Listener(){
public void onServerNotification(Notification n){
handler.post(new Runnable(){
// update UI
});
}
});
I personally don't like this at all... my instinct is that only the Client should be interacting with it's ServerManager. In order to make that the case I have to propogate the "onServerNotification" event from the ServerManager to the Client and THEN to the UI:
Code:
Client c = new Client();
c.addNotificationListener(new Client.ServerNotificationListener(){
public void onServerNotification(Notification n){
handler.post(new Runnable(){
// update UI
});
}
});
This seems a lot cleaner to me, however, in order to do this, I need the ServerManager to tell its parent Client object to issue the notification it just received:
In ServerManager:
Code:
// Called when we receive a notification
public void onReceivedNotification(Notification n)
{
Client c = null;
if( (c = _client.get()) == null )
return;
c.onReceivedNotification(n); // calls onServerNotification for each ServerNotificationListener added to the Client
}
This part I don't like. Because this required that Client have a public method which loops through the list of listeners and issues the callback to each one. I don't think such a method should be public. That exposes behaviour to other parts of the application which have no business accessing it (random parts of the app should not be able to trick the Client into thinking it received a server notifiction).
SO that leaves me adding a protected Listener to the Client which listens to its own ServerManager for onReceivedNotification events. The UI then adds an ServerNotificationListener to the Client, and when the Client receives the event from it's ServerManager, it passes it along to the UI:
ServerManager:
Code:
// Called when we receive a notification
public void onReceivedNotification(Notification n)
{
// Listener is a ServerManager.Listener
if( this.listener != null )
this.listener.onReceivedNotification(n);
}
Client:
Code:
public Client()
{
serverManager = new ServerManager();
serverManager.setListener(new ServerManager.Listener(){
public void onReceivedNotification(Notification n)
{
for(ServerNotificationListener listener : this.serverNotificationListeners)
listener.onServerNotification(n);
}
});
}
Finally, from the UI layer...
MainActivity:
Code:
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
this.client = new Client();
this.client.addServerNotificationListener(new ServerNotificationListener(){
public void onServerNotification(final Notification n)
{
handler.post(new Runnable(){
public void run()
{
// update UI with values from notification
}
});
}
});
}
So that's where I'm at now. I like the current implementation for its encapsulation. It seems clean to me. However, it also seems like it might be overly convoluted...
I'm sure this is a common problem, and I'd like to find the best solution possible -- if anyone out there has a better way, or can think of a good reason why this is TOO convoluted, I'd appreciate your comments.
Cheers!
PS. I typed all that code directly into the browser, so if there are any errors, or you can't tell what it's meant to do, please ask. The intention of the code is what matters here.