Interfaces y polimorfismo
Una interfaz es un contrato: «quien me implemente tendrá estos métodos». El polimorfismo es tratar igual a objetos distintos que cumplen el mismo contrato.
✓ En esta sub-lección
- 01Declarar una interfaz e implementarla en varias clases.
- 02Recorrer una lista de objetos distintos que cumplen el mismo contrato y tratarlos igual.
- 03Elegir entre interfaz y clase abstracta según haya o no código común.
La nutria: ¿Te acuerdas? · Repaso de la lección 9
format(Decimal) y format(Decimal, String) en la misma clase son…
La herencia dice «es un». Pero muchas veces lo que importa no es qué es un objeto, sino qué sabe hacer: puntuar un lead, ejecutarse de madrugada, ordenarse en una lista. Una describe exactamente eso: una capacidad, sin decir cómo se consigue.
La nutria: El paralelo de Admin
Declarar e implementar
public interface LeadScoringRule {
Integer score(Lead candidate); // solo la firma: sin cuerpo
}
public class IndustryRule implements LeadScoringRule {
public Integer score(Lead candidate) {
return candidate.Industry == 'Technology' ? 20 : 0;
}
}
public class SizeRule implements LeadScoringRule {
public Integer score(Lead candidate) {
Integer employees = candidate.NumberOfEmployees ?? 0;
return employees >= 500 ? 30 : 0;
}
}- La interfaz solo lista firmas: nombre, parámetros y tipo de retorno. No tiene atributos ni cuerpo.
- implements LeadScoringRule obliga a la clase a tener todos esos métodos, públicos. Si falta uno, no compila.
- Una clase puede implementar varias interfaces a la vez (implements A, B) y, además, heredar de una clase.
Polimorfismo: tratar igual lo que es distinto
Aquí está la recompensa. Una List<LeadScoringRule> puede guardar reglas de clases distintas, y el bucle que las recorre no necesita saber cuál es cuál: llama a score() y cada una responde a su manera. Para añadir una regla nueva mañana, escribes una clase y la metes en la lista; el bucle no se toca.
List<LeadScoringRule> rules = new List<LeadScoringRule>{
new IndustryRule(),
new SizeRule()
};
Lead candidate = new Lead(LastName = 'Kim', Company = 'Globex',
Industry = 'Technology', NumberOfEmployees = 800);
Integer total = 0;
for (LeadScoringRule rule : rules) {
total += rule.score(candidate); // cada regla a su manera
}
System.debug(total); // 50List<LeadScoringRule> rules
EL BUCLE · no cambia nunca
Integer total = 0;
for (LeadScoringRule r : rules) {
total += r.score(candidate);
}- IndustryRuleTechnology → 20+20
- SizeRule≥ 500 → 30+30
- CountryRuleSpain → 10—
total = 50. Activa o quita reglas: el total cambia y el bucle sigue siendo el mismo, porque solo conoce el contrato —score()— y no qué clase hay detrás. Añadir la regla del trimestre que viene es escribir una clase nueva, sin tocar nada más.
Interfaces que ya existen en la plataforma
| Interfaz | Te obliga a tener… | Para qué |
|---|---|---|
| Schedulable | execute(SchedulableContext ctx) | Programar la clase desde Setup (Módulo 9) |
| Queueable | execute(QueueableContext ctx) | Trabajo asíncrono encadenable (Módulo 9) |
| Database.Batchable | start, execute y finish | Procesar millones de registros (Módulo 9) |
| Comparable | compareTo(Object other) | Que list.sort() sepa ordenar tus objetos |
| Interfaz | Clase abstracta | |
|---|---|---|
| ¿Tiene código común? | No, solo firmas | Sí, además de métodos abstractos |
| ¿Cuántas por clase? | Todas las que quieras | Una sola (extends) |
| Úsala cuando… | compartes una capacidad | compartes una base y código |
Por qué no un if por cada tipo
Podrías escribir el scoring con un bucle y una cadena de if: si es la regla del sector, haz esto; si es la del origen, esto otro. Funciona el primer trimestre. El segundo, Marketing añade dos reglas y alguien tiene que abrir el bucle, añadir ramas y volver a probarlo todo, arriesgando las reglas que ya funcionaban. Con la interfaz, añadir una regla es escribir una clase nueva y meterla en la lista: el bucle que calcula el total no se toca nunca. Es el mismo razonamiento que en el Módulo 7 llevó las reglas de casos a clases de servicio: lo que cambia a menudo se aísla de lo que no debería cambiar.
La nutria: El elemento Subflow solo conoce el contrato
La nutria: ¿Y por qué no un Flow? Porque un flow no elige el subflow al ejecutarse