Maison >interface Web >js tutoriel >TypeScript pour la conception basée sur le domaine (DDD)

TypeScript pour la conception basée sur le domaine (DDD)

Patricia Arquette
Patricia Arquetteoriginal
2024-12-25 17:18:14509parcourir

Domain-Driven Design (DDD) est une approche puissante pour aborder les systèmes logiciels complexes en se concentrant sur le domaine métier principal et sa logique associée. TypeScript, avec sa frappe puissante et ses fonctionnalités modernes, est un excellent outil pour mettre en œuvre efficacement les concepts DDD. Cet article explore la synergie entre TypeScript et DDD, offrant des informations pratiques, des stratégies et des exemples pour combler le fossé entre la conception et le code.

Comprendre la conception basée sur le domaine

Concepts de base

1. Langue omniprésente
Collaboration entre développeurs et experts du domaine utilisant un langage partagé pour réduire les problèmes de communication.

2. Contextes délimités
Séparation claire des différentes parties du domaine, garantissant autonomie et clarté dans des contextes spécifiques.

3. Entités et objets de valeur

  • Entités : Objets avec une identité unique.
  • Objets de valeur : objets immuables définis par leurs attributs.

4. Granulats
Clusters d'objets de domaine traités comme une seule unité pour les modifications de données.

5. Dépôts
Résume la logique de persistance, donnant accès aux agrégats.

6. Événements de domaine
Signaux émis lorsque des actions significatives se produisent au sein du domaine.

7. Services applicatifs
Encapsulez les flux de travail métier et la logique d'orchestration.

Pourquoi TypeScript convient à DDD

1. Typage statique : Une vérification de type forte permet de modéliser explicitement la logique du domaine.
2. Interfaces : Appliquer les contrats entre les composants.
3. Classes : Représentent naturellement les entités, les objets de valeur et les agrégats.
4. Type Guards : Assurer la sécurité du type au moment de l'exécution.
5. Types d'utilitaires : Activez des transformations de type puissantes pour les domaines dynamiques.

Mise en œuvre pratique

1. Entités de modélisation
Les entités ont des identités uniques et encapsulent le comportement.

class Product {
  constructor(
    private readonly id: string,
    private name: string,
    private price: number
  ) {}

  changePrice(newPrice: number): void {
    if (newPrice <= 0) {
      throw new Error("Price must be greater than zero.");
    }
    this.price = newPrice;
  }

  getDetails() {
    return { id: this.id, name: this.name, price: this.price };
  }
}



2. Créer des objets de valeur
Les objets de valeur sont immuables et comparés par valeur.

class Money {
  constructor(private readonly amount: number, private readonly currency: string) {
    if (amount < 0) {
      throw new Error("Amount cannot be negative.");
    }
  }

  add(other: Money): Money {
    if (this.currency !== other.currency) {
      throw new Error("Currency mismatch.");
    }
    return new Money(this.amount + other.amount, this.currency);
  }
}



3. Définir des agrégats
Les agrégats garantissent la cohérence des données au sein d'une limite.

class Order {
  private items: OrderItem[] = [];

  constructor(private readonly id: string) {}

  addItem(product: Product, quantity: number): void {
    const orderItem = new OrderItem(product, quantity);
    this.items.push(orderItem);
  }

  calculateTotal(): number {
    return this.items.reduce((total, item) => total + item.getTotalPrice(), 0);
  }
}

class OrderItem {
  constructor(private product: Product, private quantity: number) {}

  getTotalPrice(): number {
    return this.product.getDetails().price * this.quantity;
  }
}



4. Implémentation de référentiels
Accès aux données abstraites des référentiels.

interface ProductRepository {
  findById(id: string): Product | null;
  save(product: Product): void;
}

class InMemoryProductRepository implements ProductRepository {
  private products: Map<string, Product> = new Map();

  findById(id: string): Product | null {
    return this.products.get(id) || null;
  }

  save(product: Product): void {
    this.products.set(product.getDetails().id, product);
  }
}



5. Utilisation des événements de domaine
Les événements de domaine informent le système des changements d'état.

class DomainEvent {
  constructor(public readonly name: string, public readonly occurredOn: Date) {}
}

class OrderPlaced extends DomainEvent {
  constructor(public readonly orderId: string) {
    super("OrderPlaced", new Date());
  }
}

// Event Handler Example
function onOrderPlaced(event: OrderPlaced): void {
  console.log(`Order with ID ${event.orderId} was placed.`);
}



6. Services applicatifs
Les services d'application coordonnent les flux de travail et appliquent les cas d'utilisation.

class OrderService {
  constructor(private orderRepo: OrderRepository) {}

  placeOrder(order: Order): void {
    this.orderRepo.save(order);
    const event = new OrderPlaced(order.id);
    publishEvent(event); // Simulated event publishing
  }
}

7. Travailler avec des contextes délimités

Exploitez les capacités modulaires de TypeScript pour isoler les contextes délimités.

  • Utilisez des répertoires distincts pour chaque contexte.
  • Définir explicitement des interfaces pour la communication inter-contextuelle.

Exemple de structure :

class Product {
  constructor(
    private readonly id: string,
    private name: string,
    private price: number
  ) {}

  changePrice(newPrice: number): void {
    if (newPrice <= 0) {
      throw new Error("Price must be greater than zero.");
    }
    this.price = newPrice;
  }

  getDetails() {
    return { id: this.id, name: this.name, price: this.price };
  }
}

Fonctionnalités avancées

Types conditionnels pour une modélisation flexible

class Money {
  constructor(private readonly amount: number, private readonly currency: string) {
    if (amount < 0) {
      throw new Error("Amount cannot be negative.");
    }
  }

  add(other: Money): Money {
    if (this.currency !== other.currency) {
      throw new Error("Currency mismatch.");
    }
    return new Money(this.amount + other.amount, this.currency);
  }
}

Types de littéraux de modèles pour la validation

class Order {
  private items: OrderItem[] = [];

  constructor(private readonly id: string) {}

  addItem(product: Product, quantity: number): void {
    const orderItem = new OrderItem(product, quantity);
    this.items.push(orderItem);
  }

  calculateTotal(): number {
    return this.items.reduce((total, item) => total + item.getTotalPrice(), 0);
  }
}

class OrderItem {
  constructor(private product: Product, private quantity: number) {}

  getTotalPrice(): number {
    return this.product.getDetails().price * this.quantity;
  }
}

Mon site personnel : https://shafayet.zya.me


Eh bien, cela montre à quel point vous êtes actif dans Git-toilet...

TypeScript for Domain-Driven Design (DDD)


L'image de couverture a été réalisée à l'aide d'OgImagemaker par

@eddyvinck .Merci mec de nous avoir offert cet outil ???...

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn