I have been working on a little project where it was required to use the C2 architecture. If you've never heard of this architectural style, you are in the great majority. It was developed by the Institute for Software Research at the University of California, Irvine.
It is event-based or better "component and message"-based. Components communicate using messages sent through a connector. What is interesting about it is that it differentiates between type of messages as "Notifications" and "Requests". Notifications are sent "down" and the component has no expectation that some other component is listening whereas Requests are sent "up" and the component sending them makes the assumption that the service will be provided by some other component above it (but it doesn't care who).p>Being somewhat of a departure from classic Object Oriented thinking, some of its principles are difficult to grasp. One difficulty when using this style is that events are asynchronous and run in different threads, so you don't know exactly when a message will be received or what its content will be. Another difficulty is the temptation to pass a pointer to other component and both modify it (which is not allowed).
Its advantages are clear when you put it to work: its components are very loosely coupled as no component makes any assumptions as who will provide the services and no component sees the components below listening for its notifications, if any. You can exchange one component for another (or several others) and nothing will have to be changed in the rest of the application. You could even add a whole new layer (such as a network layer) without the components noticing it. As I see it, its main disadvantage is that even though components below waiting for services "assume" those services will be provided sooner or later, there is no way to check that at compile time (nor runtime, except by noting that the notification never arrived), so your design must be pretty well thought and you must make sure you have not removed the component that was providing it by mistake.
There exists a framework that provides the machinery needed to map the components and connectors using an XML file, messaging queuing facilities and abstract classes for components and connectors.