Heim > Web-Frontend > js-Tutorial > TypeScript für Domain-Driven Design (DDD)

TypeScript für Domain-Driven Design (DDD)

Patricia Arquette
Freigeben: 2024-12-25 17:18:14
Original
629 Leute haben es durchsucht

Domain-Driven Design (DDD) ist ein leistungsstarker Ansatz zur Bewältigung komplexer Softwaresysteme, der sich auf die Kerngeschäftsdomäne und die damit verbundene Logik konzentriert. TypeScript ist mit seiner starken Typisierung und seinen modernen Funktionen ein hervorragendes Werkzeug, um DDD-Konzepte effektiv umzusetzen. Dieser Artikel untersucht die Synergie zwischen TypeScript und DDD und bietet praktische Einblicke, Strategien und Beispiele, um die Lücke zwischen Design und Code zu schließen.

Domain-Driven Design verstehen

Kernkonzepte

1. Allgegenwärtige Sprache
Zusammenarbeit zwischen Entwicklern und Domänenexperten unter Verwendung einer gemeinsamen Sprache, um Missverständnisse zu reduzieren.

2. Begrenzte Kontexte
Klare Trennung verschiedener Teile der Domäne, um Autonomie und Klarheit innerhalb spezifischer Kontexte zu gewährleisten.

3. Entitäten und Wertobjekte

  • Entitäten: Objekte mit einer einzigartigen Identität.
  • Wertobjekte: Unveränderliche Objekte, die durch ihre Attribute definiert werden.

4. Aggregate
Cluster von Domänenobjekten, die bei Datenänderungen als eine Einheit behandelt werden.

5. Repositorys
Abstrahiert die Persistenzlogik und bietet Zugriff auf Aggregate.

6. Domain-Ereignisse
Signale, die ausgegeben werden, wenn bedeutende Aktionen innerhalb der Domain stattfinden.

7. Anwendungsdienste
Kapseln Sie Geschäftsabläufe und Orchestrierungslogik.

Warum TypeScript zu DDD passt

1. Statische Typisierung: Eine starke Typprüfung hilft dabei, die Domänenlogik explizit zu modellieren.
2. Schnittstellen:Verträge zwischen Komponenten durchsetzen.
3. Klassen: Stellen Entitäten, Wertobjekte und Aggregate auf natürliche Weise dar.
4. Typschutz:Gewährleisten Sie die Typsicherheit zur Laufzeit.
5. Dienstprogrammtypen: Aktivieren Sie leistungsstarke Typtransformationen für dynamische Domänen.

Praktische Umsetzung

1. Modellierungseinheiten
Entitäten haben eindeutige Identitäten und kapseln ihr Verhalten.

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 };
  }
}
Nach dem Login kopieren
Nach dem Login kopieren



2. Wertobjekte schaffen
Wertobjekte sind unveränderlich und werden nach Wert verglichen.

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);
  }
}
Nach dem Login kopieren
Nach dem Login kopieren



3. Aggregate definieren
Aggregate stellen die Datenkonsistenz innerhalb einer Grenze sicher.

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;
  }
}
Nach dem Login kopieren
Nach dem Login kopieren



4. Repositories implementieren
Repositorys abstrahieren den Datenzugriff.

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);
  }
}
Nach dem Login kopieren



5. Verwenden von Domänenereignissen
Domänenereignisse benachrichtigen das System über Statusänderungen.

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.`);
}
Nach dem Login kopieren



6. Anwendungsdienste
Anwendungsdienste koordinieren Arbeitsabläufe und erzwingen Anwendungsfälle.

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
  }
}
Nach dem Login kopieren

7. Arbeiten mit begrenzten Kontexten

Nutzen Sie die modularen Funktionen von TypeScript, um begrenzte Kontexte zu isolieren.

  • Verwenden Sie für jeden Kontext separate Verzeichnisse.
  • Definieren Sie explizit Schnittstellen für die kontextübergreifende Kommunikation.

Beispielstruktur:

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 };
  }
}
Nach dem Login kopieren
Nach dem Login kopieren

Erweiterte Funktionen

Bedingte Typen für flexible Modellierung

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);
  }
}
Nach dem Login kopieren
Nach dem Login kopieren

Vorlagenliteraltypen für die Validierung

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;
  }
}
Nach dem Login kopieren
Nach dem Login kopieren

Meine persönliche Website: https://shafayet.zya.me


Nun, es zeigt, wie aktiv Sie in Git-Toilette sind...

TypeScript for Domain-Driven Design (DDD)


Das Titelbild wurde mit OgImagemaker von

erstellt @eddyvinck .Danke Mann, dass du uns dieses Werkzeug geschenkt hast???...

Das obige ist der detaillierte Inhalt vonTypeScript für Domain-Driven Design (DDD). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage