I am building an open source library that I can sum up to something like that:
class SuperThing {
public function doStuff($object) {
// ...
}
}
I want to offer the possibility to the user of the library to add custom behavior.
For example, he might want to insert some logging at specific points in the operation, or he might want to modify the object at a certain point.
I see 2 ways of doing it:
the template method pattern seems appropriate, but it will force me to add a lot of protected method (like beforeDoingThingA()
, afterDoingThingA()
…), and it will force the user of the library to extend my class to add his behavior.
using events: SuperThing::doStuff()
raises events, the user can register to whichever he wants.
Using events seems simpler, clearer and more maintenable to me...
But it seems to me that events would be mainly about dispatching a message that something happened. No letting someone "hook" into the operation and modify some objects. Maybe I'm wrong about this.
So are events appropriate for this situation? If not, is there an alternative to the template method pattern?
Subscribing to events should be optional; if you're OK with that, they're a possibility.
Every time I've implemented the Template Method pattern I've regretted it. It assumes that the client of the library (often a later version of me) always wants to:
DoA();
// do some hardcoded or non-virtual stuff
DoB();
// ...
DoC();
Inevitably I want to change the order of A, B, and C, change the hardcoded stuff, or something else that's outside what I (or another developer) thought of when writing the template. I'm trying to write Open-Closed code, and I often fail.
Using small components and composing them is one other option; Dependency Injection is another. A third is leaning more towards functional programming and passing delegates or function pointers to methods, or composing functions. Every option has its strengths and weaknesses; I don't think there is one right answer.
You can always combine multiple patterns. In this example why not provide both an Events system AND template methods? That way users can chose one or the other (or both) to do what they want.
However, depending on what you are doing template method might not be enough. I often find if I am making a "pipeline" that I write small interchangeable components that users can string together in various combinations to do what they want AND also listen for events fired off when the pipeline is run.
The pipeline is pretty simple, it just executes the components in the provided order (so I guess that's the Command pattern) and the pipeline and the components can both fire event to listeners.