Software Engineering

Maîtriser les motifs de conception GoF en Go

Les motifs de conception sont des solutions récurrentes aux problèmes courants en conception logicielle. Le Gang of Four (GoF) les classe en trois types principaux : Créationnels, Structurels et Comportementaux. Dans cet article, nous explorons des implémentations réelles en Go, en mettant l'accent sur la clarté, la simplicité et le code idiomatique. Que vous construisiez des microservices ou des monolithes complexes, la compréhension de ces motifs vous aide à écrire un code maintenable, évolutif et testable.

Motifs de création : Création d'objets

Les motifs de création traitent des mécanismes de création d'objets, en essayant de créer des objets d'une manière adaptée à la situation. Le plus courant est la Méthode de Fabrique (Factory Method).

Méthode de Fabrique en Go

En Go, les méthodes de fabrique basées sur les interfaces sont idiomatiques. Considérons un système de paiement prenant en charge plusieurs processeurs :

type PaymentProcessor interface {
    Process(amount float64) error
}

type StripeProcessor struct{}

func (s StripeProcessor) Process(amount float64) error {
    fmt.Printf("Processing $%.2f via Stripe\n", amount)
    return nil
}

type PayPalProcessor struct{}

func (p PayPalProcessor) Process(amount float64) error {
    fmt.Printf("Processing $%.2f via PayPal\n", amount)
    return nil
}

func NewPaymentProcessor(provider string) PaymentProcessor {
    switch provider {
    case "stripe":
        return StripeProcessor{}
    case "paypal":
        return PayPalProcessor{}
    default:
        return nil
    }
}

Ceci découple le code client des implémentations concrètes. Vous pouvez facilement ajouter de nouvelles méthodes de paiement sans modifier le code existant, conformément au Principe Ouvert/Fermé.

Motifs structurels : Composition d'objets

Les motifs structurels traitent de la manière dont les classes et les objets sont composés pour former des structures plus grandes. Le Motif Adaptateur (Adapter Pattern) est crucial pour intégrer des interfaces incompatibles.

Motif Adaptateur en Go

Supposons que vous ayez une interface de journalisation (logging) héritée qui diffère du journaliseur de votre application moderne :

type LegacyLogger interface {
    Log(msg string)
}

type AppLogger interface {
    Info(msg string)
    Error(msg string)
}

type LoggerAdapter struct {
    legacy LegacyLogger
}

func (a LoggerAdapter) Info(msg string) {
    a.legacy.Log("[INFO] " + msg)
}

func (a LoggerAdapter) Error(msg string) {
    a.legacy.Log("[ERROR] " + msg)
}

func NewLoggerAdapter(legacy LegacyLogger) AppLogger {
    return LoggerAdapter{legacy: legacy}
}

Cet adaptateur permet à votre application moderne d'utiliser le journaliseur hérité sans modifier son interface, favorisant la réutilisation du code et le refactorisation progressive.

Motifs comportementaux : Interaction entre objets

Les motifs comportementaux concernent les algorithmes et l'attribution des responsabilités entre les objets. Le Motif Observateur (Observer Pattern) est vital pour les architectures pilotées par les événements.

Motif Observateur en Go

Les canaux (channels) de Go fournissent une implémentation naturelle du motif Observateur pour la communication asynchrone :

type Event struct {
    ID   int
    Data string
}

type EventHandler func(Event)

type EventBus struct {
    handlers map[string][]EventHandler
}

func NewEventBus() *EventBus {
    return &EventBus{handlers: make(map[string][]EventHandler)}
}

func (eb *EventBus) Subscribe(eventType string, handler EventHandler) {
    eb.handlers[eventType] = append(eb.handlers[eventType], handler)
}

func (eb *EventBus) Publish(event Event) {
    for _, handler := range eb.handlers["order"] {
        go handler(event)
    }
}

func main() {
    bus := NewEventBus()
    bus.Subscribe("order", func(e Event) {
        fmt.Printf("Email sent for order %d\n", e.ID)
    })
    bus.Subscribe("order", func(e Event) {
        fmt.Printf("Notification sent for order %d\n", e.ID)
    })
    bus.Publish(Event{ID: 1, Data: "New Order"})
}

Ce découplage lâche permet à plusieurs abonnés de réagir aux événements sans se connaître, ce qui est idéal pour les microservices et les systèmes pilotés par les événements.

Conclusion

Les motifs de conception ne sont pas des solutions universelles, mais plutôt des modèles éprouvés qui abordent les défis architecturaux courants. Les motifs de création simplifient la création d'objets, les motifs structurels gèrent les relations entre les objets, et les motifs comportementaux gèrent la communication. En Go, exploitez les forces du langage comme les interfaces et les canaux pour implémenter ces motifs de manière idiomatique. N'oubliez pas : choisissez des motifs qui résolvent votre problème spécifique et ne les forcez pas là où ils ne s'appliquent pas. Maîtriser ces motifs élèvera votre code du niveau fonctionnel à un niveau robuste et maintenable.

Share: