Clases de servicio
El handler sabe de eventos; la regla de negocio no debería. Sacarla a una clase de servicio es lo que permite que un botón, un proceso nocturno y el trigger usen exactamente la misma regla.
✓ En esta sub-lección
- 01Distinguir lo que es del handler (traducir eventos) de lo que es del servicio (la regla de negocio).
- 02Escribir un servicio con métodos static que reciben listas y no saben nada de triggers.
- 03Decidir quién guarda: el servicio cambia registros, quien lo llama decide si hace falta DML.
- 04Reutilizar la misma regla desde otra puerta distinta del trigger.
La nutria: ¿Te acuerdas? · Repaso de la lección 2
¿Qué debe quedar dentro del trigger delgado?
Soporte está contento: la prioridad ya sale bien. Tan contento que pide más: un botón «Recalcular prioridad» para los casos antiguos, creados antes de que existiera la regla. Y Operaciones quiere revisar cada noche los casos del día. La regla es la misma; lo que cambia es la puerta por la que se entra. Si la regla vive en beforeInsert, ninguna de esas puertas tiene sentido llamándola.
QUIEN LLAMA
CaseTriggerHandler.beforeInsert(newCases)SIEMPRE EL MISMO SERVICIO
CaseEscalationService.applyPriorityRules(cases)↳ No hace falta update: en before, Salesforce guarda solo.
El handler recibe los casos del trigger y le pide al servicio que aplique la regla. El servicio no sabe que viene de un trigger: solo recibe una lista.
La nutria: Ya lo hacías con subflows
Qué es del handler y qué es del servicio
| Handler | Servicio | |
|---|---|---|
| Sabe de… | Eventos: before, after, insert, update. | El negocio: cuentas Hot, prioridades, tareas. |
| Quién lo llama | Solo su trigger. | Cualquiera: handler, botón, proceso, test. |
| Sus métodos se llaman… | Por el evento: beforeInsert. | Por lo que hacen: applyPriorityRules. |
| Cómo son sus métodos | De instancia, uno por evento. | static, reciben listas, bulk. |
Con la , el handler adelgaza hasta quedarse en lo que de verdad es suyo: decidir qué reglas se aplican en cada evento y en qué orden. Cada método del handler pasa a ser una lista de llamadas al servicio. Los métodos del servicio son static porque no guardan nada entre llamadas: reciben una lista, hacen su trabajo y terminan, como una fórmula que no recuerda la ejecución anterior (Módulo 5).
public with sharing class CaseTriggerHandler {
public void beforeInsert(List<Case> newCases) {
CaseEscalationService.applyPriorityRules(newCases);
}
public void afterInsert(List<Case> newCases) {
CaseEscalationService.createReviewTasks(newCases);
}
}
public with sharing class CaseEscalationService {
public static void applyPriorityRules(List<Case> cases) { /* la regla */ }
public static void createReviewTasks(List<Case> cases) { /* las tareas */ }
}Quién guarda: la pregunta que decide el diseño
applyPriorityRules cambia la prioridad en memoria y NO hace update. Parece un olvido, pero es la clave. Cuando la llama el handler en before insert, los casos todavía no se han guardado y Salesforce los guardará solo; un update ahí, además, fallaría, porque en un trigger before no se permite hacer DML sobre los propios registros de Trigger.new. Cuando la llama el botón, en cambio, los casos ya existen, y quien tiene que guardarlos es el botón. El servicio cambia los registros; quien lo llama decide si hace falta guardar.
public with sharing class CaseActions {
// El botón «Recalcular prioridad»: otra puerta, la misma regla
public static void recalculatePriority(Set<Id> caseIds) {
List<Case> cases = [
SELECT Id, Origin, AccountId, Priority
FROM Case
WHERE Id IN :caseIds
];
CaseEscalationService.applyPriorityRules(cases);
update cases; // aquí sí: estos casos ya existen
}
}