When we talk about event-oriented programming, we're usually talking about one or more implementations of the observer design pattern. And one goal of the observer design pattern is to achieve loose coupling between objects.
That probably doesn't mean much without a good example, and there are certainly lots of good ones out there; I doubt mine will be the best of them, but I'll take a whack at it nonetheless. Imagine two objects. One object wants to know when something happens with the other object, so it can do something itself -- maybe the family dog, Rover, wants to greet Dad at the door when he gets home from work. There are a couple of ways you might program that scenario, right?
Make sure Dad has an reference to Rover, and when he comes home, call Rover's greetDatAtTheDoor() method, or
Give Rover a reference to dad,
listen for Dad's onArriveHome event,
and when it fires, call
greetDadAtTheDoor() internally.
On the surface, there might not seem to be much difference between the two, but actually, Dad has some of Rover's implementation burned into him; if Rover's implementation had to change for some reason, we'd have to make changes in two places: once in Rover, and then again in Dad. Not a huge deal, maybe, but still, not ideal.
Now imagine Mom wants to greet Dad as well. And the cat, Mr. Bigglesworth, who doesn't like Dad very much, wants to make sure he's not around, so he'd rather go outside. And a neighbor, Joe, wants to know when Dad gets home, so he can bug him about that twenty bucks Dad owes him. How do we account for all those scenarios, and the additional ones that'll inevitably crop up? Placing references to Mom's greetHusband() method, the cat's getOutNow() method, the dog's greetDadAtTheDoor() method, and Joe's goGetMyMoney() method into Dad's class definition would mess things up fast for Dad -- and for no good reason, since all Dad really needs to do, himself, is come home. Mom, the dog, the cat, and the neighbor just want to be notified when that happens, so they can do whatever their internal implementations require.
Languages handle the specifics of this stuff in different ways, but as you'll see when you start Googling around, the pattern usually involves there being an array, or array-like structure, on the event "dispatcher" (in this case, Dad -- i.e., the object everyone else is interested in), and the "subscribers" (e.g., Mom, the cat, Rover, and Joe) all "register" by calling a publicly exposed method on the dispatcher and passing in references to themselves -- references that end up, in some form, in Dad's array of "subscribers." Then, when Dad comes home, he "dispatches" an event -- the "I'm home!" event, say -- which is essentially a function that loops over each of his subscribers and invokes them with some publicly accessible method of their own -- only it's a method whose name Dad doesn't know, doesn't have to know, because the listener provided it when he/she/it passed it in.
Since I happen to code mostly ActionScript these days, here's how it might look in my world -- say, as declared from within my Mom class:
var dad:Dad = new Dad();
dad.addEventListener(DadEvent.ARRIVED_HOME, greetHusbandAtDoor);
private function greetHusbandAtDoor(event:DadEvent):void
{
// Go greet my husband
}
In Dad, then, all I have to do, when I come home, is:
dispatchEvent(new DadEvent(DadEvent.ARRIVED_HOME));
... and because Flash handles the event-dispatching and notification details for me (again, everyone does it a bit differently, but internally, Flash follows the conceptual model I've described), my Dad comes home, and each family member does what it signed up to do automatically.
Hopefully that explains things a bit -- what event-thinking looks like, what loose coupling means, why it's important, and so on. Best of luck!