A collection of learnings and opinions.

Showing posts with label patterns. Show all posts
Showing posts with label patterns. Show all posts

Monday, March 5, 2007

Tell Me When Something Happens

Events are a staple of object-oriented design. They are a way decoupling objects and that is almost always a good thing. A short synopsis of the idea:

You have some object (Foo) and you want to be able to know when something happens to Foo. Say Foo is a button and you want to know when it's been pressed in order to do something. You could just code Foo to do the thing you wanted, but then you'd have to code every button for everything you want to do. You could tell Foo to execute some method (possibly in some other Object) when it was pressed, but then you'd lock Foo and the method together. You'd have problems if someone later changed that method also, as they may not know that Foo calls it. The solution to this is to let Foo have events, and code the actual behavior in some other Object or method which handles that event.

In Java this is done through a pattern called the event-listener. I call it that, anyway. What you do is you let Foo implement a method that takes the listener (addListener(FooListener l)).

public class Foo {
private List(FooListener) listeners = new LinkedList(FooListener);

public void addListener(FooListener l) {
listeners.add(l);
}
}


FooListener is an interface that includes one method to handle the event when the listener gets it. You can put whatever you want into the FooEvent, depending on what kind of event your particular implementation raises. Often you only need to send an event, that's enough information in itself.

public interface FooListener {
public void handleEvent(FooEvent e);
}


In Foo you decide when you want to send an event to the listeners, and you do it something like this:
private void doSomething() {
for(FooListener l : listeners) {
l.handleEvent(new FooEvent("Something"));
}
}


This works, but it's a bit verbose, and worse - it's up to the developers to decide how to do this and if they will.

In .Net classes have events themselves. The engineers over at MS have taken this pattern and hardcoded it into their platform. So, what you do here is slightly different:

Events and listeners are what I know from Java, but in VB.NET they're called Events and Handlers. I can live with that, it parses. What's really cool though is that like properties (which I really like) the events are language-features. So, you've got some kind of standard to follow, it's not something you have to explore on your own or make up on the spot.

When you add a button in VB.NET your app already knows about the events that can generate (they are part of the specification of the Button class). This makes it easy for the code-generator to give you the boilerplate for a handler. In fact, that's what it does when you double-click a button in the form-designer. Coding has never been so easy, and I like that.

The problem with this easy code-generation (for me, and this may be a problem with me) is that it doesn't teach you how to do this yourself. My case was that I wanted to add a handler to a control that only exists after a certain set of actions have been taken in my program.

When I add a handler to a button which exists the code is easy. Let's say I have a button called btnFoo on my form. To handle a click from this I just type in (VB.Net):
Public Sub handleButtonFoo(ByVal sender as System.Object, ByVal e as System.EventArgs) Handles btnFoo.Click
Console.Out.WriteLine("Click")
End Sub


It gets a little more hairy when you're handling dynamically created Objects, though. This took me some time to find, and it led me to a foray into delegates. I'll get back to them some other time though.

What you have to do is create a method with the same signature as the event. Say I'm looking to handle a LostFocus event on a Control. That has the signature: Public Event LostFocus(ByVal sender As Object, ByVal e As System.EventArgs). So what I need is a method that matches that signature. Behold!

Private Sub HandleSomethingLostFocus(ByVal sender As System.Object, ByVal a As EventArgs)
Console.Out.WriteLine("Give me back my focus!")
End Sub


This is not the whole story though. You may have noticed that the handleButtonFoo method had the keyword handles after it with a reference to the event it wanted. My little lost-focus method has no such thing, as no object exists yet that I want to handle. When one exists though, I can pipe the events to my method with the following code:
Private Sub createWidget()
'Make something that can lose focus
Dim widget As New TextBox

'Add the widget to the main form (which we're in)
Me.Controls.Add(widget)

'pipe the LostFocus events to the handler we wrote
AddHandler widget.LostFocus, AddressOf Me.HandleSomethingLostFocus

End Sub


This will delegate the LostFocus events to my method. Yay!

As you may have noticed this is a better way to handle this than in Java. You get a set pattern on how to do it, defined at the language level (AddHandler is a reserved word). It's also less verbose than the Java-way, as that one included code in two classes and one interface. It may do the same, but I like it better.

Now I've got to get home, I have a sick child. Till next time!

Thursday, March 1, 2007

I'm Thinking of Something Round

I was having this little problem with the app I'm developing. It's the same program that I've been talking about the last two posts, the unnamed application I'm calling Pluto. The problem I'm addressing this time is not domain-specific however, but rather a result of my lack of experience with the platform and language I'm using.

I was looking to present parameters in a GUI for the user to manipulate. I'd solved the tasks of getting the parameters from the web service and presenting them in controls based on their type. Getting the parameters into the user's face is only half the work, though. I also had to get the user's input back into Pluto's guts somehow. Now, this gave me a few sorts of problems.

The first problem is that I know the user is interacting with a control, and I know which kind of control it is. Thus, one might think I could easily map the control-type to the parameter-type. It works, for dates, strings and booleans. It's not so easy for integers and floats though, as they're both most easily displayed with what .net calls a NumericUpDown (lovely little things). As you may know you can set the number of decimals such a control allows.

I briefly toyed with the idea of setting integer-type controls to have 0 decimals and floats to have some other number and parsing based on that. All this was starting to smell of a hack. I was taking some arbitrary subset of the data contained in a datatype (the original ReportParameter), using it to construct some other object (the Control) and then trying to make a new object of the original type with that small subset of data and some implicit knowledge (what kind of control each parameter type mapped to). Badness.

How do I get out of this bad situation I've gotten myself into? It's obvious that I want to keep the original object, and just get the changes (if any) from the control into it. That would be much better, safer, cheaper (well, not in memory but we're talking about on the order of 0-10 objects here) and much, much less buggy. Just imagine trying to maintain such a mapping if you've really no idea what I did and why...

How do I keep the original objects? One solution would be a global list of the original objects with the same numbering as the controls I added (or some other arbitrary scheme to keep the control-parameter mapping). This is not an ideal solution - it's not very object-oriented, the mapping is non-obvious and globals tend to be a bad idea for these kinds of problems. So, I kept thinking.

When I keep thinking I can come up with some really convoluted and complex solutions to problems like this. My though was this: If I make an object that includes both the original parameter and the control I can just ask it to return the parameter. The immediate problem with this is that I would loose the elegance of adding controls directly to the GUI. Could I somehow solve this by making the object an extension of the Control? If I were a .net -guru I could possibly do this in some way and easily make such an object. I am not, however, I am brand new at this platform and totally new at VB.NET. So, I looked around, read a bit, tried to understand how this plot could be hatched, but I really got nowhere.

This got me thinking about patterns, though. I like patterns, so I tried to identify what I was trying to do. Was my problem solved by a proxy? Well, no, I didn't really need an object to stand-in for another. I had access to the control, I wanted to add functionality. Could it be a composite? Not really that either, as composites are good at unifying the way you use some number (usually a substantial number) of components. It had to be a decorator, the pattern that lets you add some functionality to some existing object (by "painting" that functionality onto it). It may seem obvious now, but it's never that easy when you're thinking through it. At least it isn't for me, caveat emptor.

I had it licked. I just had to implement the pattern that "painted" the original object onto the controller. Why was I not happy? This was a tiny, but important part of Pluto, and going straight on to implementation of a decorator-pattern with interfaces and implementations et cetera wasn't what I wanted to do. I still had a hope, maybe just a wish, that I wouldn't have to go through that for this simple need.

I'd skimmed the definition of the Control to see if there was anything I could use in there at the beginning of this problem, but nothing particularly stood out. I was probably just putting off starting on the pattern, but I found myself reading through it again. I was scanning for any kind of Object-reference the Control could keep - maybe I could just put it in there? I found a few, but they all sounded like they changed the behaviour of the control in some significant manner (AccesibilityObject? No, I don't like the sound of that). Then I found it: the control has a property called a Tag, and it's an Object.

You know that combination of elation and shame you get when you see that a problem you've spent good time on has already been solved? Not only has it been solved, but it's right there in front of you ready to be used. Let me quote the description of the Tag from the API: Gets or sets the object that contains data about the control. Could it be better?

So, slightly shamed but mostly happy about the way the problem had been solved elegantly and without any implementation whatsoever I simply tagged the controls with the parameters. This means that I can get the original object directly when I parse the input from the user, get the content that's been changed and send the whole shebang back to the server.

Right now I really love that.

My professor once told me: "A few hours in a library can frequently save you months of research."