I know Trigger templates are previously discussed also in great detail. We have excellent posts available by Steve Andersen(Gokubi) and Mike Leach on the same. Here is my small journey on Triggers
I started developing on force.com, I used bare bone approach as mentioned in Apex developer guide.
After sometime I was using something similar to what Steve mentioned in his blog, I was happy to see that Steve suggested a similar practice.
Eventually tried something that is similar to what Mike suggested in his blog.
After trying all of the above trigger templates, I was still not happy when working solo or when working with a big team of engineers on the same project. I wanted something simple to adopt easily with flexibility to extend/add as required.
So, I started working on a new trigger templates with these motives in mind
Framework/Base template code to start writing a new trigger should be minimal or none.
It should allow any complex and reusable trigger code to be written.
It should allow easy fixes other commonly visible problems, like trigger firing twice, as explained by Ray Dehler.
Optionally create handlers with @future support.
Ability to easily order and add multiple handlers on a single trigger event.
Yet Another Trigger Template !
“Triggers.cls” is the new Trigger template. This class doesn’t needs to be copied per sobject trigger and will be reused throughout the org. Here is the code snippet for it
Using the template
We will again follow the same one trigger per Sobject rule and just write handlers for each event like before insert, after update etc. Handlers can be created by implementing interface “Triggers.Handler”, only contract of this interface is to write all the trigger logic using the Trigger context variables as and when required. Here are a few sample handlers(these handlers can be nested into one big class to avoid too many classes)
Now the actual Task trigger will be as follows
Feedback
Looking forward for your views and thoughts on the same. I’m sure it’s a good topic to discuss and debate on.
Comments (18)
Anonymoussays:
January 2, 2012 at 5:51 pmpublic Triggers bind(Evt event, Handler eh) { // Check via containsKey first, and populate empty list if (!eventHandlerMapping.containsKey(event.name()) { eventHandlerMapping.put(event.name(), new List()); } // Then query out eventHandlerMapping.get(event.name()).add(eh); return this;}
Anonymoussays:
January 2, 2012 at 6:20 pmThanks for the suggestion Ryan, I believe the way you handle maps as we did in bind method is more of individual taste i.e containsKey vs null check !
Anonymoussays:
January 16, 2012 at 9:38 amNice one Abhinav! +1 for using the Builder pattern. :)I'll definitely try it out.
Anonymoussays:
January 16, 2012 at 10:31 amThanks Anup, yes its inspired from Builder 🙂 good catch !!
Anonymoussays:
February 2, 2012 at 5:26 pmHow can I use the same handler for both let say afterinsert/afterupdate actions?
Anonymoussays:
February 3, 2012 at 4:36 amI will update the post for the same Max, stay tuned !
Anonymoussays:
February 3, 2012 at 9:05 amThanks, Abhinav! Post is great! Another question that I've got while playing with the code: is there a better way of type casting other then (SomeCustomObject)sobj in handlers?
Anonymoussays:
February 3, 2012 at 9:16 amHey Max,Great point, this cast would be required unfortunately, until Salesforce comes with GENERICS support for apex classes.
Anonymoussays:
August 7, 2012 at 2:54 pmVery nice, Abhinav!Did you extend this for a handler for multiple events, like Max asked earlier?That would really make me like this pattern the best!
Anonymoussays:
August 7, 2012 at 2:57 pmThanks Heuvel,The template supports multiple events, as indicated in the updated example i.e.new Triggers() .bind(Triggers.Evt.afterinsert, new TaskAfterInsertHandler()) // bind first before insert handler .bind(Triggers.Evt.beforeinsert, new TaskBeforeInsertHandler()) // bind another before insert handler, that will execute after the first one. // All you need to do is add handlers in the correct order here .bind(Triggers.Evt.beforeinsert, new TaskBeforeInsertHandler2()) .bind(Triggers.Evt.afterupdate, new TaskAfterUpdateHandler()) // Done with adding all handlers, lets call the manage now for once only .manage();To reuse same handler, you can do that, as trigger context variables like Trigger.new, Trigger.isBefore, Trigger.isInsert are available in the apex class.I would love to discuss it more, if you have any questions.
Anonymoussays:
November 26, 2012 at 3:34 pmHey Abhinav, I made some edits that I am curious for your feedback on. Some of the “enhancements” I was trying to implement were:1. Prevent the trigger from firing over and over again when undesired (trigger firing twice). 2. Executing the bind code for several actions (before and after) or for subsequent triggers on the same objects seemed unnecessary and added to script statement limits. 3. Get all logic out of the triggers themselves.I built a gist for my code: https://gist.github.com/4148705The next enhancement I would like to add would be to lazy load object data across TriggerFunctions to prevent unnecessary redundant SOQL statements.
Anonymoussays:
November 27, 2012 at 2:55 amThanks Justin for feedback, I will check this and revert back soon.
Anonymoussays:
November 27, 2012 at 3:44 pmLooks fine to me Justin, more of a personal taste on how we want to go around it. Few suggestions- TriggerManager is TriggerExecutor actually, as its not managing anything – TriggerHandler could be using Builder pattern, so this would lead to a TriggerBuilder with a Trigger instance ready to be executed by TriggerExecutor http://en.wikipedia.org/wiki/Builder_pattern#Java – main() is a starting class function name in Java, so being from that background it looks confusing to me. – We don't need dynamic type initalization here, as we can change TriggerManager.execute (String) to TriggerManager.execute(TriggerHandler) and Account trigger can easily call TriggerManager.execute(new AccountTriggerHandler()), this will retain references correctly between classes ( a problem with dynamic string based initalizations).
Anonymoussays:
December 31, 2012 at 2:27 pmVery impressive. Best use of object oriented concepts to handle triggers and a clean interface. Nice job Abhinav.
Anonymoussays:
December 31, 2012 at 2:28 pmNice clean implementation and good use of object oriented design pattern. Great job Abhinav
Anonymoussays:
December 31, 2012 at 2:30 pmThanks Anil, glad you liked it !
Anonymoussays:
March 21, 2013 at 1:43 pmThanks for great codes. However I met a problem. when I try to iterate Trigger.new in my handler class it gives error:Loop variable must be of type SObjectit looks like you cannot use Trigger.new outside of trigger?
Anonymoussays:
March 21, 2013 at 2:02 pmThats true Xiao, explicit cast is needed from Sobject to the actual one. As of now Generics support is not available in Apex, so thats the limitation 🙁