Value Objects
Value Objects
Qu'est-ce qu'un Value Object ?
Un Value Object est un concept du Domain-Driven Design (DDD) qui représente un objet défini uniquement par ses attributs, sans identité propre. Contrairement aux entités qui sont identifiées par un ID unique, deux Value Objects avec les mêmes attributs sont considérés comme identiques.
Les caractéristiques essentielles des Value Objects sont :
- Immutabilité : Une fois créés, ils ne peuvent pas être modifiés.
- Égalité basée sur les attributs : Deux Value Objects sont égaux si tous leurs attributs sont égaux.
- Auto-validation : Ils garantissent leur propre validité.
- Encapsulation de concept : Ils représentent un concept cohérent du domaine métier.
Exemples de Value Objects courants
Voici quelques exemples typiques de Value Objects :
- Adresse postale
- Montant monétaire (avec devise)
- Numéro de téléphone
- Adresse email
- Plage de dates
- Coordonnées géographiques
Exemples en PHP
Value Object simple : Email
Value Object avec opérations : Money
Utilisation des Value Objects
Exemples en Go
Value Object simple : Email
package main
import (
"errors"
"fmt"
"regexp"
"strings"
)
type Email struct
var emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`)
func NewEmail(address string) (Email, error)
func () string
func () string
func (other Email) bool
func () string
Value Object avec opérations : Money
package main
import (
"errors"
"fmt"
"math"
"strings"
)
type Money struct
func NewMoney(amount float64, currency string) (Money, error)
func () float64
func () string
func (other Money) bool
func (other Money) (Money, error)
func (other Money) (Money, error)
func (factor float64) (Money, error)
func (ratios []int) ([]Money, error)
func () string
Utilisation des Value Objects en Go
func main()
Implémentation des Value Objects
Principes d'implémentation
Immuabilité : Ne fournissez aucune méthode qui modifie l'état interne. Toute opération qui "modifie" l'objet doit retourner une nouvelle instance.
Validation au constructeur : Toute validation doit être effectuée lors de la création de l'objet, garantissant que toutes les instances sont valides.
Comparaison d'égalité : Implémentez une méthode d'égalité qui compare tous les attributs pertinents.
Méthodes métier : Ajoutez des méthodes qui ont un sens dans le contexte métier (comme
getDomain()
pour un email).Représentation sous forme de chaîne : Implémentez une méthode de conversion en chaîne pour faciliter l'affichage et le débogage.
Value Objects vs Primitive Obsession
La Primitive Obsession est un anti-pattern qui consiste à utiliser des types primitifs (chaînes, nombres, booléens) pour représenter des concepts métier complexes. Les Value Objects sont la solution à ce problème.
Avantages par rapport aux primitives
Validation intégrée : Les Value Objects valident leur contenu, contrairement aux primitives qui acceptent n'importe quelle valeur.
Comportement enrichi : Ils peuvent contenir des méthodes spécifiques au domaine, comme
formatPhoneNumber()
pour un numéro de téléphone.Prévention des erreurs : Le système de types empêche de mélanger des concepts différents (par exemple, un
EmailAddress
ne peut pas être utilisé à la place d'unPhoneNumber
).Documentation implicite : Le code devient plus expressif et auto-documenté.
Quand utiliser des Value Objects ?
Les Value Objects sont particulièrement utiles dans les situations suivantes :
- Lorsque vous avez besoin d'effectuer des opérations sur une valeur (comme l'addition de montants).
- Quand des règles de validation spécifiques doivent être appliquées.
- Lorsque la valeur est utilisée dans plusieurs endroits du code.
- Quand des comportements spécifiques sont associés à la valeur.
- Pour éviter les confusions entre différents types de données similaires (comme différents types d'identifiants).
Avantages des Value Objects
- Immutabilité : Réduction des erreurs liées à la modification accidentelle des données.
- Clarté sémantique : Représentation claire et explicite des concepts métier.
- Encapsulation de la validation : Les règles métier sont définies une seule fois à l'endroit approprié.
- Testabilité : Plus facile à tester car immuable et sans effets secondaires.
- Sécurité : Prévention des erreurs de type et de validation.
Inconvénients des Value Objects
- Complexité du code : Plus de classes et de fichiers à gérer.
- Sérialisation : Nécessite des adaptateurs pour la conversion vers/depuis des formats comme JSON.
- Performance : La création de nombreux objets peut avoir un impact sur les performances dans certains cas.
- Courbe d'apprentissage : Requiert une compréhension des principes du DDD et des bonnes pratiques.
Conclusion
Les Value Objects constituent un outil fondamental dans le Domain-Driven Design pour représenter des concepts métier de manière claire, immuable et auto-validante. Bien qu'ils introduisent une certaine complexité, leurs avantages en termes de clarté, de sécurité et de robustesse du code en font un élément essentiel dans la boîte à outils du développeur soucieux de créer un code qui reflète fidèlement le domaine métier.
La transition de la Primitive Obsession vers l'utilisation de Value Objects est l'un des refactorings les plus bénéfiques pour améliorer la qualité et la maintenabilité du code.
Ressources
- Domain-Driven Design: Tackling Complexity in the Heart of Software par Eric Evans
- Implementing Domain-Driven Design par Vaughn Vernon
- Value Objects in Domain-Driven Design par Martin Fowler
- Refactoring from Anemic Domain Model to the Rich One
- Value Object: A Better Implementation
