I have an application where I'd like to add ways for external modules/components to hook during the processes and data-flow and perform actions/modify data.
For the first requirement—performing actions—I assume the best pattern would be to emit events and have other modules/components subscribe to those events and perform their actions, correct?
The second requirement is where it gets very tricky for me, I will try to explain it with an example:
someObject = {
... // properties and stuff
performComputation: function() {
let data = this.data;
return this.x * data.amount;
}
}
Now, I want a way to perform dynamic modifications on some value of that function, and maybe the return
value. What I want to achieve is very similar to what WordPress does with filter
hooks. WordPress maintains an array of callbacks to call in a certain order to allow for data manipulation. If I implement something similar, my code would look like this:
someObject = {
... // properties and stuff
performComputation: function() {
let data = applyFilters('computationData', this.data);
return applyFilters('computationResult', this.x * data.amount);
}
}
and I could then hook into that using an API which would look like this:
addFilter('computationResult', (res) => { return res * 2; });
This obviously works, but by the fact that I have never seen this pattern used in any JS library and the fact that with hours of research I didn't find anyone implementing a simple node module about that, I have the impression this might be an anti-pattern that I should avoid (I understand it can become messy and hard to debug, for example).
So, here are my questions:
- What's this pattern called? Maybe I just don't know how to search for it.
- Has this anything to do with Aspect Oriented Programming?
- Would there be a better pattern approach that I am not thinking about that would fulfill my requirements? Specifically: (1) hooking into parts of the applications to manipulate data (2) hooks need to be added and removed fairly often during the user interaction with the application.
Edit
It seems that my goal is being misunderstood, so I'll try to explain it better. The Observable pattern or Event dispatching allows me to run code within the execution of another code. However, the reason why it is not enough for me is specifically because Observers don't return values that can be manipulated.
As for AOP, as pointed out by Candied Orange's answer, the target doesn't know it's being hooked on. Which is also not my goal.
My goal is for a function to expose certain pieces of data for other functions to hook on and manipulate.
Again, with another example pseudo-code:
someObject = {
name: "Jim",
greet: function(str) {
let greeting = applyFilters('greeting', str);
return `${greeting} I am ${name}.`;
}
}
addFilter('greeting', (str) => { return str.toUppercase(); });
addFilter('greeting', (str) => { return str + "!!"; });
someObject.greet("Hello"); // => HELLO!! I am Jim.
This is the kind of functionality I need, and it can be easily implemented with iterating over callbacks as I mentioned, but I am not sure if this is in any way a good pattern or if I have alternatives to achieve this goal.