[JAVA] Erstellen eines Beispielprogramms mit dem Problem eines Datenbankspezialisten mit DDD-Verbesserung 1

Einführung

Das letzte Mal schrieb ich einen Artikel, in dem ich versuchte, ein Beispielprogramm mit DDD unter Verwendung des Problems eines Datenbankspezialisten zu erstellen.

Ich habe ein Beispielprogramm mit dem Problem des Datenbankspezialisten für domänengesteuertes Design erstellt

Vielen Dank an alle, die im Kommentarbereich und auf Twitter kommentiert haben. Es gab viele Dinge, die nicht gut liefen, und ich denke, es ist wichtig, sich weiter zu verbessern und auszugeben. Deshalb wollte ich in diesem Artikel einen überarbeiteten Artikel veröffentlichen.

Von den drei Endpunkten "Anmeldeschluss beantragen", "Lotterieergebnisse registrieren" und "Einzahlung" wurde "Anmeldeschluss beantragen" dieses Mal überarbeitet.

Der Quellcode lautet hier Die Version zum Zeitpunkt der Veröffentlichung dieses Artikels ist Tag 1.1.

Erstellen Sie ein Domänenmodelldiagramm

Ich hatte das Gefühl, dass die Modellierung nicht gut gemacht wurde, also @ little_hand_s [Was ist DDD-Modellierung und wie man sie in den Code einfügt](https://www.slideshare.net/koichiromatsuoka/domain-modeling- Ich habe ein Domänenmodelldiagramm mit Bezug auf die Folie mit dem Namen andcoding erstellt.

参加申込.png

Der der Geschäftsregel entsprechende Teil wird aus den Prüfungsfragen herausgeblasen. Alle diese Sprechblasen sind an diesem Einstiegspunkt nicht mit dem Programm verbunden, aber es war schön, die in der Domänenschicht zu schreibende Logik organisieren zu können.

Von der Anwendungsschicht zur Domänenschicht

Im vorherigen Programm wurde der Teil "Mitglieder können die Teilnahme an nur einem Anmeldungsrahmen für ein Turnier beantragen" in die Anwendungsschicht übertragen, daher habe ich versucht, ihn in die Domänenschicht zu verschieben.

An @ a-suenami im vorherigen Kommentarbereich

Ich denke zum Beispiel, dass die Bedingung, dass "nur ein Eintragsrahmen für ein Turnier angewendet werden kann", ein Anliegen der Domäne ist. Erstellen Sie daher anstelle von if im Anwendungsdienst einen Typ wie die Richtlinie zur Annahme von Turnieranwendungen (FestivalApplicationPolicy). Ich denke, es ist besser, es in das Domain-Modell zu setzen.

Ich erhielt die Meinung, dass ich versucht habe, dies auf meine eigene Weise umzusetzen.

FestivalApplicationPolicy.java


public class FestivalApplicationPolicy {

  private List<Application> applicationList;

  public FestivalApplicationPolicy(List<Application> applicationList) {
    this.applicationList = new ArrayList<>(applicationList);
  }

  /**
   *Gibt zurück, ob das durch das Argument angegebene Mitglied bereits die Teilnahme an dem durch das Argument angegebenen Turnier beantragt hat.
   *Gibt true zurück, wenn es bereits angewendet wurde.
   */
  boolean hasAlreadyApplyForSameFestival(MemberId memberId, FestivalId festivalId) {

    for (Application application : applicationList) {
      if (application.festivalId().equals(festivalId)
          && application.memberId().equals(memberId)) {
        return true;
      }
    }

    return false;
  }
}

Ich benutze eine erstklassige Sammlung. Ich habe eine Liste von Teilnahmeanträgen in diesem Bereich, und wenn es einen Teilnahmeantrag mit derselben Mitgliedsnummer und Turniernummer gibt, habe ich versucht zu beurteilen, dass der Teilnahmeantrag bereits ausgefüllt wurde.

Ich habe versucht, dies in dem später beschriebenen Domänendienst zu verwenden.

Erstellen eines Domänendienstes

Ich musste eine Entität erstellen, um die Anwendung beizubehalten, und ich habe einen Domänendienst erstellt, um diese Entität zu erstellen. (Der Name ist verwirrend, aber ich erstelle ihn in der Domänenschicht anstelle der Anwendungsschicht.) Ich bin mir immer noch nicht sicher, wie ich den Domänendienst gut nutzen soll, und ich habe mich gefragt, ob ich ihn mit der statischen Methode in der Entität der Teilnahmeanwendung erstellen soll, aber diesmal habe ich es so gemacht.

ApplicationService.java


public class ApplicationService {

  private Entry entry;

  private FestivalApplicationPolicy festivalApplicationPolicy;

  /**
   *Konstrukteur.
   */
  public ApplicationService(
      Entry entry, FestivalApplicationPolicy festivalApplicationPolicy) {

    this.entry = entry;
    this.festivalApplicationPolicy = festivalApplicationPolicy;
  }

  /**
   *Erstellen Sie ein Teilnahmeantragsobjekt und geben Sie es zurück.
   * @Objekt der Teilnahme-Anwendung zurückgeben
   */
  public Application createApplication(MemberId memberId, LocalDate applicationDate)
      throws EntryStatusIsNotRecruitingException,
      HasAlreadyApplyForSameFestivalException {

    //Teilnahmeanträge werden nur akzeptiert, solange der Startplatz offen ist
    if (entry.entryStatus() != EntryStatus.recruiting) {
      throw new EntryStatusIsNotRecruitingException();
    }

    //Die Beurteilung auf der Grundlage des Startdatums der Einstellung und des Enddatums der Einstellung sollte erfolgen, wenn der Status des Einstiegsrahmens derzeit eingestellt wird.
    //Da kein Fehler auftreten sollte, wage ich es, hier eine IllegalStateException auszulösen.
    if (applicationDate.compareTo(entry.applicationStartDate()) < 0) {
      throw new IllegalStateException("Das angegebene Turnier hat noch nicht mit der Rekrutierung begonnen");
    }

    if (applicationDate.compareTo(entry.applicationEndDate()) > 0) {
      throw new IllegalStateException("Die Rekrutierungsfrist für das vorgesehene Turnier ist abgelaufen");
    }


    //Mitglieder können die Teilnahme an nur einem Startplatz für ein Turnier beantragen
    if (festivalApplicationPolicy.hasAlreadyApplyForSameFestival(
        memberId, entry.festivalId())) {
      throw new HasAlreadyApplyForSameFestivalException();
    }

    return Application.createEntityForEntry(
        entry.festivalId(),
        memberId,
        entry.entryId(),
        applicationDate
    );
  }
}

Nach dem Aktivieren von "Teilnahmeantrag nur annehmen, während der Anmeldungsrahmen rekrutiert wird", "Mitglieder können nur für einen Anmeldungsrahmen für ein Turnier die Teilnahme beantragen" usw., wenn kein Fehler vorliegt, bleibt das Objekt der Anmeldeklasse bestehen Wird generiert und zurückgegeben.

Wir erstellen auch Geschäftsausnahmeklassen mit den Namen "EntryStatusIsNotRecruitingException" und "HasAlreadyApplyForSameFestivalException". Dies wurde auch von @ a-suenami gegeben

Ich möchte die Nachrichtenzeichenfolge selbst behandeln, die dem Benutzer im Anwendungsdienst angezeigt wird, aber ich denke, dass es sich bei einem Fehler um ein Domänenobjekt handeln kann. Daher möchte ich es als Aufzählungstyp zurückgeben.

Ich habe es mit Bezug auf den Kommentar versucht. Ich verwende jedoch Ausnahmen anstelle von Aufzählungstypen. Ich habe mich gefragt, ob das Feld für die Geschäftsausnahmeklasse einen Aufzählungstyp hat, der den Fehlertyp anzeigt, aber ich dachte, dass diese beiden Fehler auch für die Partizipationsanwendungsdomäne von Interesse sind, und habe daher eine Ausnahmeklasse im Partizipationsanwendungsdomänenpaket erstellt. Diese Ausnahme wird in der Anwendungsschicht abgefangen, damit Fehlermeldungen behandelt werden können.

Vergleich der Anwendungsebene

Die Programme für die Bewerbung für die Teilnahme an der Bewerbungsschicht beim letzten Mal und diesmal sind wie folgt.

** Letztes Mal **

ApplicationCommandService.java


  /**
   *Bewerben Sie sich für den Einstiegsplatz.
   */
  public void applyForEntry(ApplyForEntryRequest request) {

    final FestivalId festivalId = request.festivalId();
    final MemberId memberId = request.memberId();
    final EntryId entryId = request.entryId();
    final LocalDate applicationDate = request.getApplicationDate();

    final Member member = memberRepository.findMember(request.memberId());
    if (member == null) {
      throw new BusinessErrorException("Es ist ein Mitglied, das nicht existiert");
    }

    final Application alreadyApplication =
        applicationRepository.findApplication(festivalId, memberId);

    if (alreadyApplication != null) {
      throw new BusinessErrorException("Ich habe mich bereits für das angegebene Turnier beworben");
    }

    final Entry entry = entryRepository.findEntry(festivalId, entryId);

    if (entry == null) {
      throw new BusinessErrorException("Es ist ein Eintragsrahmen, der nicht existiert");
    }

    final Application application = Application.createEntityForEntry(
        festivalId,
        memberId,
        entryId,
        applicationDate
    );

    entry.validateAndThrowBusinessErrorIfHasErrorForApplication(application);

    entry.incrementApplicationNumbers();
    entryRepository.saveEntry(entry);

    applicationRepository.addApplication(application);
  }

diesmal

ApplicationCommandService.java


  /**
   *Bewerben Sie sich für den Einstiegsplatz.
   */
  public void applyForEntry(ApplyForEntryRequest request) {

    final FestivalId festivalId = request.festivalId();
    final EntryId entryId = request.entryId();
    final MemberId memberId = request.memberId();
    final LocalDate applicationDate = request.getApplicationDate();

    final Member member = memberRepository.findMember(memberId);
    if (member == null) {
      throw new BusinessErrorException("Es ist ein Mitglied, das nicht existiert");
    }

    final Entry entry = entryRepository.findEntry(festivalId, entryId);
    if (entry == null) {
      throw new BusinessErrorException("Es ist ein Eintragsrahmen, der nicht existiert");
    }

    final FestivalApplicationPolicy festivalApplicationPolicy =
        applicationRepository.createFestivalApplicationPolicy(festivalId, memberId);

    final ApplicationService applicationService =
        new ApplicationService(entry, festivalApplicationPolicy);

    final Application application;
    try {
      application = applicationService.createApplication(memberId, applicationDate);
    } catch (EntryStatusIsNotRecruitingException e) {
      throw new BusinessErrorException("Das vorgesehene Turnier rekrutiert derzeit nicht");
    } catch (HasAlreadyApplyForSameFestivalException e) {
      throw new BusinessErrorException("Ich habe mich bereits für das angegebene Turnier beworben");
    }

    entry.incrementApplicationNumbers();
    entryRepository.saveEntry(entry);

    applicationRepository.addApplication(application);
  }

Generieren Sie den Domänendienst "ApplicationService" mit dem Eintragsrahmenobjekt "Eintrag" und der neu erstellten "FestivalApplicationPolicy" als Argumente, generieren Sie die Beteiligungsanwendungsentität "Anwendung" mit "ApplicationService" und machen Sie sie persistent. Ich habe es gemacht. Es sieht nicht nach viel Veränderung aus, aber zumindest konnten wir "Mitglieder können sich nur für einen Eintrittsplatz für ein Turnier bewerben" auf die Domain-Ebene verschieben.

schließlich

In diesem Fall ist dies möglicherweise nicht sehr vorteilhaft, aber durch Wiederholen von Verbesserungen, die die Interessen der Domain auf die Domain-Ebene bringen, kann das Programm im tatsächlichen Geschäft leicht geändert werden! !! Es sollte sein: heat_smile: Durch das Wiederholen von Verbesserungen durch Refactoring sollten sich auch die Designfähigkeiten verbessern, sodass ich in naher Zukunft die Einstiegspunkte für "Lotterieergebnisse registrieren" und "Einzahlung" umgestalten und einen Artikel schreiben werde.

Vielen Dank, dass Sie so weit gelesen haben. Kommentare von allen Ich bin sehr glücklich und habe viel zu lernen, daher würde ich mich freuen, wenn Sie Kommentare abgeben könnten.

Recommended Posts

Erstellen eines Beispielprogramms mit dem Problem eines Datenbankspezialisten für DDD-Verbesserung 2
Erstellen eines Beispielprogramms mit dem Problem eines Datenbankspezialisten mit DDD-Verbesserung 1
Ich habe versucht, ein Beispielprogramm mit dem Problem des Datenbankspezialisten für domänengesteuertes Design zu erstellen
Beispielprogramm, das den Hashwert einer Datei in Java zurückgibt
Verwenden der Datenbank (SQL Server 2014) aus einem Java-Programm 2018/01/04
Ein Programm, das die Anzahl der Wörter in einer Liste zählt
Ein Memorandum über das FizzBuzz-Problem
Reihenfolge der Verarbeitung im Programm
Erstellen eines Servlets in der Liberty-Umgebung
Ich habe ein Beispiel erstellt, wie ein Delegat in Swift UI 2.0 mit MapKit geschrieben wird
Messen Sie die Größe eines Ordners mit Java
Beispielcode zum Zuweisen eines Werts in der Eigenschaftendatei zu einem Feld des erwarteten Typs
Ich habe versucht, eine Datenbankverbindung in der Android-Entwicklung zu verwenden
Über das Problem des Deadlocks bei der Parallelverarbeitung in gem'sprockets '4.0
Ich habe ein Sequenzdiagramm des j.u.c.Flow-Beispiels geschrieben
[Ruby] Gewöhnen Sie sich an, beim Erstellen einer Kopie einer Zeichenfolgenvariablen die dup-Methode zu verwenden
Ein Programm (Java), das die Summe von ungeraden und geraden Zahlen in einem Array ausgibt
Beispielcode zum Abrufen der Werte der wichtigsten SQL-Typen in Java + Oracle Database 12c
Erstellen Sie eine Datenbank aller Bücher, die im letzten Jahrhundert in Japan im Umlauf waren
Ich habe versucht, ein Programm in Java zu erstellen, das das Problem des Handlungsreisenden mit einem genetischen Algorithmus löst
Vorlagenerstellungsprogramm bei Verwendung der Erinnerungsfunktion im Ruhezustand
Eine kurze Erklärung der fünf Arten von Java Static
Verfahren zum Veröffentlichen einer Anwendung mit AWS (4) Erstellen einer Datenbank
Erklärung von Ruby on Rails für Anfänger ③ ~ Erstellen einer Datenbank ~
Finden Sie mit Kotlin die Anzahl der Tage in einem Monat