Open/Closed Principle
Ouvert à l'extension, fermé à la modification
Principe
Un module doit être ouvert à l'extension (on peut ajouter des comportements) mais fermé à la modification (on ne touche pas au code existant pour le faire).
En pratique : ajouter une fonctionnalité ne doit pas nécessiter de modifier du code existant qui fonctionne.
Violation classique
type DiscountType = 'vip' | 'student' | 'employee';
function calculateDiscount(price: number, type: DiscountType): number {
if (type === 'vip') return price * 0.8;
if (type === 'student') return price * 0.85;
if (type === 'employee') return price * 0.7;
return price;
}Chaque nouvelle réduction nécessite de modifier calculateDiscount. Si cette fonction est dans un package externe ou partagé entre équipes, c'est un problème.
Application de l'OCP
interface DiscountStrategy {
apply(price: number): number;
}
const vipDiscount: DiscountStrategy = {
apply: (price) => price * 0.8,
};
const studentDiscount: DiscountStrategy = {
apply: (price) => price * 0.85,
};
const employeeDiscount: DiscountStrategy = {
apply: (price) => price * 0.7,
};
// calculateDiscount ne change plus
function calculateDiscount(price: number, strategy: DiscountStrategy): number {
return strategy.apply(price);
}
// Ajouter une réduction = ajouter un objet, pas modifier calculateDiscount
const seasonalDiscount: DiscountStrategy = {
apply: (price) => price * 0.9,
};En React : les render props et les slots
OCP se retrouve naturellement dans la conception de composants React réutilisables.
// Fermé : le composant Card impose son rendu interne
function Card({ title, content }: { title: string; content: string }) {
return (
<div className="card">
<h2>{title}</h2>
<p>{content}</p>
</div>
);
}
// Ouvert : le parent contrôle ce qui est rendu
function Card({ title, children }: { title: string; children: React.ReactNode }) {
return (
<div className="card">
<h2>{title}</h2>
{children}
</div>
);
}
// Le composant Card ne change pas quand on veut afficher autre chose
<Card title="Produit">
<ProductDetails product={product} />
<AddToCartButton productId={product.id} />
</Card>Nuance
OCP ne signifie pas qu'on ne modifie jamais rien. Si une règle métier change fondamentalement, il faut modifier le code. L'idée est d'anticiper les points de variation connus et de les rendre extensibles, sans suringénierie pour des cas hypothétiques.