DDD serialisierter Artikel
Was sagt Eric Evans zur Definition von DDD In diesem Artikel habe ich geschrieben, dass die Definition der domänengetriebenen Entwicklung wie folgt lautet:
- Konzentrieren Sie sich auf die Kernkomplexität und die Möglichkeiten der Domäne
Wie wird das verbalisierte Modell des Domänenwissens letztendlich im Code dargestellt?
Wenn Sie über geschäftliche Einschränkungen nachdenken, denken Sie zunächst an *** invariante Bedingungen ***.
Invariante Bedingung: Eine Bedingung, die während der gesamten Lebensdauer des Modells konsistent sein muss.
Es gibt verschiedene Namen wie Spezifikationen und Einschränkungsbedingungen, aber der Begriff invariante Bedingung wird als Begriff für DDD verwendet, sodass wir ihn vereinheitlichen werden.
Angenommen, Sie möchten eine Aufgabe in einer Geschäftsanwendung modellieren. Nachdem ich die Anforderungen definiert hatte, stellte ich fest, dass die folgenden invarianten Bedingungen erfüllt sein müssen.
Lassen Sie uns dies implementieren.
@Entity
public class Task {
@Id
@GeneratedValue
private Long id;
private TaskStatus taskStatus;
private String name;
private LocalDate dueDate;
private int postponeCount;
public static final int POSTPONE_MAX_COUNT = 3;
public Task() {
}
/*
*Setter für alle Artikel
*/
public void setId(Long id) { this.id = id; }
public void setTaskStatus(TaskStatus taskStatus) { this.taskStatus = taskStatus; }
public void setName(String name) { this.name = name; }
public void setDueDate(LocalDate dueDate) { this.dueDate = dueDate; }
public void setPostponeCount(int postponeCount) { this.postponeCount = postponeCount; }
/*
*Besser für alle Artikel
*/
public Long getId() { return this.id; }
public String getName() { return this.name; }
public TaskStatus getTaskStatus() { return this.taskStatus; }
public LocalDate getDueDate() { return this.dueDate; }
public int getPostponeCount() { return this.postponeCount; }
/*
*Eine Methode, die kaum Verhalten hat
*/
public boolean canPostpone() { return this.postponeCount < POSTPONE_MAX_COUNT; }
}
public enum TaskStatus {
UNDONE, DONE
}
public class TaskApplication {
@Autowired
private TaskRepository taskRepository;
public void createTask(String name, LocalDate dueDate) {
if (name == null || dueDate == null) {
throw new IllegalArgumentException("Erforderliche Elemente sind nicht festgelegt");
}
Task task = new Task();
task.setTaskStatus(TaskStatus.UNDONE);
task.setName(name);
task.setDueDate(dueDate);
task.setPostponeCount(0);
taskRepository.save(task);
}
public void postponeTask(Long taskId) {
Task task = taskRepository.findById(taskId);
if (!taks.canPostpone()) {
throw new IllegalArgumentException("Die maximale Anzahl von Verschiebungen wurde überschritten");
}
task.setDueDate(task.getDueDate().plusDays(1L));
task.setPostponeCount(task.getPostponeCount() + 1);
taskRepository.save(task);
}
//Die Abschlussverarbeitung entfällt
}
Es ist fertig! Es sieht so aus, als würde es die Anforderungen erfüllen. In der TaskApplication-Klasse scheint es kein Problem mit der Erstellung und Aktualisierung von Aufgaben zu geben. Lassen Sie es uns jetzt veröffentlichen.
Einige Wochen nach der Veröffentlichung hat jedoch ein Ingenieur, der mit dem Geschäft nicht vertraut ist, den folgenden Code implementiert.
public class AnotherTaskApplication {
@Autowired
private TaskRepository taskRepository;
public void createDoneTask(String name, LocalDate dueDate) {
Task task = new Task();
task.setTaskStatus(TaskStatus.DONE); //× Aufgabengenerierung im abgeschlossenen Zustand
task.setPostponeCount(-1); //× Die Anzahl ist ein Minus
taskRepository.save(task);
}
public void changeTask(Long taskId, String name, LocalDate dueDate, TaskStatus taskStatus) {
Task task = taskRepository.findById(taskId);
task.setName(name); //× Ändern Sie den Aufgabennamen, der nicht geändert werden soll
task.setDueDate(dueDate); //× Stellen Sie das Fälligkeitsdatum beliebig mit dem Eingabewert ein und ignorieren Sie die Anzahl der Verschiebungen
task.setTaskStatu(taskStatus); //× Aufgaben können auf unvollständig zurückgesetzt werden
taskRepository.save(task); }
}
Es ist erstaunlich, dass ich die unveränderlichen Bedingungen zerstören konnte.
Das Problem besteht darin, dass die AnotherTaskAPplication-Klasse erstellt und implementiert wird, sodass die Person, die die ursprüngliche TaskApplication-Klasse implementiert hat, nicht bemerkt hat, dass eine solche Verarbeitung in einer anderen Klasse geschrieben wurde. (Lassen Sie uns das Überprüfungssystem vorerst verlassen)
In diesem Beispiel wird die Spezifikation von Application ausgedrückt, aber das Task-Modell selbst, das in allen Elementen Setter / Getter enthält, kann nichts ausdrücken.
Dieser Zustand wird als *** Domänenmodellanämie *** bezeichnet.
Dieses Objekt, das keine invarianten Bedingungen mehr darstellen kann, ist kein Modell mehr, sondern lediglich ein *** Datenmodell ***, das ein relationales Modell auf das Objekt projiziert. Und eine solche Anwendung kann als *** Transaktionsskript *** bezeichnet werden.
Wie können wir also das Modell dazu bringen, invariante Bedingungen darzustellen?
@Entity
class Task {
@Id
@GeneratedValue
private Long id;
private TaskStatus taskStatus;
private String name;
private LocalDate dueDate;
private int postponeCount;
private static final int POSTPONE_MAX_COUNT = 3;
/*
*Konstruktor: Stellt eine invariante Bedingung beim Erstellen einer Entität dar
*/
public Task(String name, LocalDate dueDate) {
if (name == null || dueDate == null) {
throw new IllegalArgumentException("Erforderliche Elemente sind nicht festgelegt");
}
this.name = name;
this.dueDate = dueDate;
this.taskStatus = TaskStatus.UNDONE;
this.postponeCount = 0;
}
/*
*Zustandsübergangsmethode: Stellt eine invariante Bedingung dar, die sich auf den Zustandsübergang einer erstellten Entität bezieht
*/
public void postpone() {
if (postponeCount >= POSTPONE_MAX_COUNT) {
throw new IllegalArgumentException("Die maximale Anzahl von Verschiebungen wurde überschritten");
}
dueDate.plusDays(1L);
postponeCount++;
}
public void done() {
this.taskStatus = TaskStatus.DONE;
}
//Es gibt keinen Namensgeber, daher können Sie den Namen nicht ändern
/*
*Getter, Zustandserfassungsmethode
*/
public Long getId() { return id; }
public String getName() { return name; }
public LocalDate getDueDate() { return dueDate; }
public boolean isUndone() { return this.taskStatus == TaskStatus.UNDONE; }
public boolean canPostpone() { return this.postponeCount < POSTPONE_MAX_COUNT; }
}
//Im selben Paket wird enum als Paket privat definiert
enum TaskStatus {
UNDONE, DONE
}
public class TaskApplication {
@Autowired
private TaskRepository taskRepository;
public void createTask(String name, LocalDate dueDate) {
Task task = new Task(name, dueDate); //Aufgabeninstanzen werden immer mit unveränderlichen Bedingungen erstellt
taskRepository.save(task);
}
public void postpone(Long taskId) {
Task task = taskRepository.findById(taskId);
task.postpone(); //Eine Verarbeitung, die unveränderliche Bedingungen zerstört, kann nicht aus der Anwendung für das erfasste Objekt geschrieben werden
taskRepository.save(task);
}
//Die Abschlussverarbeitung entfällt
//Die Validierung entfällt
}
Als der Prozess des Auferlegens invarianter Bedingungen auf das Modell übertragen wurde ... wurde ein sehr ausdrucksstarkes Modell erstellt! !!
Die invariante Bedingung wird vom Konstruktor des Task-Modells und der Zustandsübergangsmethode wunderbar ausgedrückt.
Einige der Vorteile dieses Designs sind:
Es ist eine gute Sache.
Wenn Sie dies schreiben, können Sie sagen, dass das *** Modell das Wissen über die Domäne *** ausdrückt.
Lassen Sie uns auf die domänengesteuerte Definition zurückblicken.
- Konzentrieren Sie sich auf die Kernkomplexität und die Möglichkeiten der Domäne
Mit dem obigen Beispiel konnten wir Software schreiben, die das Modell darstellt.
Dieses Design allein hat große Vorteile gehabt, aber das Domain-Fahren endet hier nicht.
Wie wird sich ein solches Modell verhalten und wie wird es sich ändern, wenn die Spezifikationen geändert werden? Indem wir die Definition von Wörtern mit Experten für Unternehmen (Domänen) abgleichen, verfolgen wir immer das neueste und ausdrucksstärkere Modell und folgen dem Code.
Dies ist buchstäblich *** domänenmodellgetriebene Entwicklung ***.
Ich hoffe, Sie lesen diesen Artikel und denken: "Oh, vielleicht DDD?" Ich werde auch in Zukunft Artikel schreiben, um DDD zu verbreiten. Bitte bleiben Sie mit mir in Kontakt, wenn Sie möchten.
Recommended Posts