Frage

Diese Frage ist sprachunabhängig, aber ich bin ein C # Kerl so dass ich den Begriff POCO verwenden, um ein Objekt zu verstehen, die Vorformen Datenspeicherung nur, in der Regel Getter und Setter-Felder verwendet wird.

ich überarbeitete gerade meine Domain Model Super-Duper POCO zu sein und bin mit einem paar Bedenken links in Bezug auf, wie sichergestellt wird, dass der Eigenschaftswert Sinn witin die Domäne zu machen.

Zum Beispiel kann die EndDate eines Dienstes sollte nicht mehr als die EndDate des Vertrages, auf dem Service unter ist. Allerdings scheint es wie eine Verletzung von SOLID den Scheck in die Service.EndDate Setter zu setzen, nicht zu erwähnen, dass die Zahl der Validierungen, die getan werden muss meine POCO Klassen wächst wird sich überladen.

Ich habe einige Lösungen (wird in Antworten posten), aber sie haben ihre Nachteile und wundere mich, was sind einige Lieblings nähert sich diesem Dilemma zu lösen?

War es hilfreich?

Lösung

Ich glaube, Sie beginnen mit einer schlechten Annahme aus, das heißt, dass Sie Objekte, die aber speichern Daten nichts zu tun haben sollte, und haben keine Methoden, sondern Accessoren. Der ganze Punkt von Objekten ist, Daten zu kapseln und Verhaltensweisen . Wenn Sie eine Sache, die gerade ist, im Grunde eine Struktur, welche Verhaltensweisen Einkapseln Sie?

Andere Tipps

Ich höre immer wieder Leute Argument für eine "Bestätigen" oder "IsValid" -Methode.

Ich persönlich denke, dies funktionieren kann, aber bei den meisten DDD Projekte beenden Sie in der Regel nach oben mit mehreren Validierungen, die in Abhängigkeit von dem spezifischen Zustand des Objekts zulässig sind.

So ziehe ich „IsValidForNewContract“, „IsValidForTermination“ oder ähnliches, weil ich die meisten Projekte am Ende mit mehreren solchen Validierer / Zuständen pro Klasse glauben. Das bedeutet auch ich keine Schnittstelle zu bekommen, aber ich kann aggregierte Validatoren schreiben, dass lesen sehr gut, die Geschäftsbedingungen widerspiegeln ich zu behaupten.

Ich glaube wirklich die allgemeinen Lösungen in diesem Fall sehr oft Fokus nehmen weg aus, was wichtig ist - was der Code tut - für eine sehr geringe Verstärkung in technischen Eleganz (die Schnittstelle, delegiert oder was auch immer ). stimmen Sie mich nach unten für sie;)

Ein Kollege von mir kam mit einer Idee, die ziemlich gut funktioniert. Wir kamen nie für ihn mit einem großen Namen, aber wir nannten es Inspektor / Richter.

Der Inspektor auf ein Objekt aussehen würde und sagen Ihnen, alle Regeln sie verletzt. Der Richter würde entscheiden, was zu tun ist. Diese Trennung lassen Sie uns ein paar Dinge tun. Er ließ uns an einem Ort (Inspektor) alle Regeln setzen, aber wir konnten mehrere Richter haben und der Richter durch den Kontext wählen.

Ein Beispiel für die Verwendung mehrerer Richter dreht sich um die Regel, dass ein Kunde gesagt muss eine Adresse hat. Dies war ein Standard-Drei-Schichten-App. In dem Benutzeroberfläche Tiere erzeugen würden die Richter etwas, das die Benutzeroberfläche die Felder nutzen könnte, um anzuzeigen, die ausgefüllt werden mußten. Die UI-Richter nicht Ausnahmen werfen. In der Dienstschicht gab es einen anderen Richter. Wenn es einen Kunden ohne Adresse beim Speichern gefunden würde es eine Ausnahme werfen. An diesem Punkt muss man die Dinge wirklich von Verfahren stoppen.

Wir hatten auch Richter, die strenger waren als der Zustand der Objekte verändert. Es war ein Versicherungsantrag und während des Prozesses Zitiert wurde eine Politik darf in einem unvollständigen Zustand gespeichert werden. Aber sobald die Politik bereit war, eine Menge Dinge gemacht werden Aktive musste eingestellt werden. So ist der Zitiert Richter auf der Serviceseite war nicht so streng wie die Aktivierung Richter. Doch die im Inspektoren verwendeten Regeln waren noch die gleiche, so könnte man noch sagen, was nicht vollständig war, auch wenn Sie nicht, etwas dagegen zu tun beschlossen.

Eine Lösung ist jedes Objekt DataAccessObject nimmt eine Liste von Validatoren zu haben. Wenn Speicher aufgerufen wird es Preforms eine Prüfung gegen jede Prüfung:

public class ServiceEndDateValidator : IValidator<Service> {
  public void Check(Service s) {
    if(s.EndDate > s.Contract.EndDate)
      throw new InvalidOperationException();
  }
}

public class ServiceDao : IDao<Service> {
  IValidator<Service> _validators;
  public ServiceDao(IEnumerable<IValidator<Service>> validators) {_validators = validators;}
  public void Save(Service s) {
    foreach(var v in _validators)
      v.Check(service);
    // Go on to save
  }
}

Der Vorteil ist ganz klar SoC ist der Nachteil, dass wir erhalten den Scheck nicht bis Save () aufgerufen wird.

In der Vergangenheit habe ich in der Regel Validierung zu einem Dienst zu seiner eigenen, wie ein ValidationService delegiert. Dies im Prinzip immer noch ad hört die Philosophie von DDD.

Intern würde dies eine Sammlung von Validatoren und einen sehr einfachen Satz von öffentlichen Methoden wie Validate () enthält, die eine Sammlung von Fehlerobjekt zurückkehren konnte.

Ganz einfach, so etwas wie dies in C #

public class ValidationService<T>
{
  private IList<IValidator> _validators;

  public IList<Error> Validate(T objectToValidate)
  {
    foreach(IValidator validator in _validators)
    {
      yield return validator.Validate(objectToValidate);
    }
  }
}

Validatoren entweder hinzugefügt innerhalb eines Standardkonstruktors werden könnte oder über eine andere Klasse wie ein ValidationServiceFactory injiziert.

ich denke, dass wahrscheinlich der beste Ort für die Logik sei, tatsächlich, aber das ist nur meine Meinung. Man könnte eine Art von IsValid Methode, die auch alle Bedingungen überprüft und gibt wahr / falsch, vielleicht eine Art von Errormessages Sammlung, aber das ist ein iffy Thema, da die Fehlermeldungen nicht wirklich ein Teil des Domain Models sind. Ich bin ein wenig voreingenommen, da ich einige Arbeit mit RoR getan habe, und das ist im Wesentlichen, was seine Modelle tun.

Eine andere Möglichkeit ist jede meiner Klassen implementieren haben

public interface Validatable<T> {
  public event Action<T> RequiresValidation;
}

Und jedes Setter haben für jede Klasse das Ereignis erhöhen, bevor Sie (vielleicht könnte ich über Attribute erreichen dies).

Der Vorteil ist, Echtzeit-Validierung Prüfung. Aber unordentlicher Code und es ist unklar, wer sollte das Anbringen tun.

Hier ist eine weitere Möglichkeit. Die Validierung erfolgt über einen Proxy oder Dekorateur auf dem Domänenobjekt gemacht:

public class ServiceValidationProxy : Service {
  public override DateTime EndDate {
    get {return EndDate;}
    set {
      if(value > Contract.EndDate)
        throw new InvalidOperationexception();
      base.EndDate = value;
    }
  }
}

Vorteil: Sofortige Validierung. Kann leicht über einen IoC konfiguriert werden.

Nachteil: Wenn ein Proxy, validiert Eigenschaften müssen virtuell sein, wenn ein Dekorateur alle Domänenmodelle Schnittstelle basiert sein müssen. Die Validierungsklassen wird ein bisschen Schwergewicht am Ende - Proxys haben, die Klasse erben und Dekorateure haben alle Methoden zu implementieren. Benennen und Organisation könnte verwirrend.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top