Interfaces & classes abstraites, polymorphisme
Objectif
Modéliser des contrats d’API avec des interfaces, factoriser du code avec des classes abstraites, utiliser le polymorphisme et des méthodes par défaut.
Exemple : stratégie
// src/pay/PaymentStrategy.java
package pay;
public interface PaymentStrategy {
boolean pay(double amount);
default boolean validateAmount(double amount) { return amount >= 0.0; }
}
// src/pay/CardPayment.java
package pay;
public class CardPayment implements PaymentStrategy {
@Override public boolean pay(double amount) {
if (!validateAmount(amount)) return false;
System.out.println("Paiement par carte: " + amount);
return true;
}
}
// src/pay/WalletPayment.java
package pay;
public class WalletPayment implements PaymentStrategy {
@Override public boolean pay(double amount) {
System.out.println("Paiement via portefeuille: " + amount);
return true;
}
}
// src/app/Checkout.java
package app;
import pay.*;
public class Checkout {
private PaymentStrategy strategy;
public void setStrategy(PaymentStrategy s) { this.strategy = s; }
public boolean process(double amount) {
if (strategy == null) throw new IllegalStateException("Strategy required");
return strategy.pay(amount);
}
public static void main(String[] args) {
Checkout c = new Checkout();
c.setStrategy(new CardPayment());
c.process(49.99);
c.setStrategy(new WalletPayment());
c.process(12.00);
}
}
Classe abstraite vs interface (exemple)
abstract class Shape {
public abstract double area();
public String description() { return getClass().getSimpleName(); }
}
interface Drawable { void draw(); }
TP (à rendre)
- Concevoir une API de
PricingRule
(interface) avecdouble apply(double base)
et une méthodedefault clamp(min,max)
. - Implémenter 3 règles : remise fixe, remise % (plafonnée), TVA.
- Créer une
abstract class Pipeline
avecapplyAll(List<PricingRule>, base)
implémentée. - Tester avec divers paniers et prouver le polymorphisme (injection d’implémentations).
Corrigé (pistes)
public interface PricingRule {
double apply(double base);
default double clamp(double v, double min, double max) { return Math.max(min, Math.min(max, v)); }
}
record FixedOff(double amount) implements PricingRule { public double apply(double base){ return Math.max(0, base - amount); } }
record PercentOff(double pct, double maxOff) implements PricingRule {
public double apply(double base){
double off = base * pct;
return base - Math.min(off, maxOff);
}
}
record Vat(double rate) implements PricingRule { public double apply(double base){ return base * (1 + rate); } }
abstract class Pipeline {
public double applyAll(java.util.List<PricingRule> rules, double base) {
double res = base;
for (var r : rules) res = r.apply(res);
return res;
}
}
Vigilances
- Une interface définit un contrat ; une classe abstraite fournit un squelette et éventuellement du code partagé.
- Préférer programmer contre une interface pour découpler.
Ce contenu est réservé aux membres du site. Si vous êtes un utilisateur existant, veuillez vous connecter. Les nouveaux utilisateurs peuvent s'inscrire ci-dessous.