it-swarm.com.de

Ein Objekt über eine eigene Methode oder über eine andere Klasse speichern?

Wenn ich ein Objekt speichern und abrufen möchte, sollte ich eine andere Klasse erstellen, um es zu verarbeiten, oder wäre es besser, dies in der Klasse selbst zu tun? Oder vielleicht beides mischen?

Welches wird nach OOD-Paradigma empfohlen?

Zum Beispiel

Class Student
{
    public string Name {set; get;}
    ....
    public bool Save()
    {
        SqlConnection con = ...
        // Save the class in the db
    }
    public bool Retrieve()
    {
         // search the db for the student and fill the attributes
    }
    public List<Student> RetrieveAllStudents()
    {
         // this is such a method I have most problem with it 
         // that an object returns an array of objects of its own class!
    }
}

Gegen. (Ich weiß, dass Folgendes empfohlen wird, aber es scheint mir ein bisschen gegen den Zusammenhalt der Klasse Student zu sein)

Class Student { /* */ }
Class DB {
  public bool AddStudent(Student s)
  {

  }
  public Student RetrieveStudent(Criteria)
  {
  } 
  public List<Student> RetrieveAllStudents()
  {
  }
}

Wie wäre es, sie zu mischen?

   Class Student
    {
        public string Name {set; get;}
        ....
        public bool Save()
        {
            /// do some business logic!
            db.AddStudent(this);
        }
        public bool Retrieve()
        {
             // build the criteria 
             db.RetrieveStudent(criteria);
             // fill the attributes
        }
    }
38
Ahmad

Prinzip der Einzelverantwortung , Trennung von Bedenken und Funktioneller Zusammenhalt . Wenn Sie sich über diese Konzepte informieren, erhalten Sie folgende Antwort: Trennen Sie sie .

Ein einfacher Grund, das Student von der "DB" -Klasse zu trennen (oder StudentRepository, um gängigeren Konventionen zu folgen), besteht darin, dass Sie Ihre "Geschäftsregeln" ändern können, die im Student Klasse, ohne den Code zu beeinflussen, der für die Persistenz verantwortlich ist, und umgekehrt.

Diese Art der Trennung ist sehr wichtig, nicht nur zwischen Geschäftsregeln und Persistenz, sondern auch zwischen den vielen Belangen Ihres Systems, damit Sie Änderungen mit minimalen Auswirkungen in nicht verwandten Modulen vornehmen können (minimal, da dies manchmal unvermeidbar ist). Es hilft, robustere Systeme zu bauen, die einfacher zu warten und bei ständigen Änderungen zuverlässiger sind.

Indem Sie Geschäftsregeln und Persistenz miteinander mischen, entweder eine einzelne Klasse wie in Ihrem ersten Beispiel oder mit DB als Abhängigkeit von Student, verbinden Sie zwei sehr unterschiedliche Probleme. Es mag so aussehen, als ob sie zusammen gehören; Sie scheinen zusammenhängend zu sein, weil sie dieselben Daten verwenden. Aber hier ist die Sache: Der Zusammenhalt kann nicht nur an den Daten gemessen werden, die zwischen den Prozeduren geteilt werden. Sie müssen auch den Abstraktionsgrad berücksichtigen, auf dem sie existieren. Tatsächlich wird die ideale Art des Zusammenhalts beschrieben als:

Funktionaler Zusammenhalt ist, wenn Teile eines Moduls gruppiert werden, weil sie alle zu einer einzigen genau definierten Aufgabe des Moduls beitragen.

Und klar, das Durchführen von Validierungen für ein Student, während es auch weiterhin besteht, bildet keine "einzelne genau definierte Aufgabe". Geschäftsregeln und Persistenzmechanismen sind also zwei sehr unterschiedliche Aspekte des Systems, die nach vielen Prinzipien eines guten objektorientierten Designs getrennt gehalten werden sollten.

Ich empfehle, über Clean Architecture zu lesen, dies spricht über das Prinzip der Einzelverantwortung (wo ein sehr ähnliches Beispiel verwendet wird) und dieses Gespräch über Clean Architecture auch. Diese Konzepte umreißen die Gründe für solche Trennungen.

34
MichelHenrich

Beide Ansätze verstoßen gegen das Prinzip der Einzelverantwortung. Ihre erste Version weist der Klasse Student viele Verantwortlichkeiten zu und bindet sie an eine bestimmte DB-Zugriffstechnologie. Die zweite führt zu einer riesigen DB Klasse, die nicht nur für die Schüler, sondern auch für jede andere Art von Datenobjekt in Ihrem Programm verantwortlich ist. BEARBEITEN: Ihr dritter Ansatz ist der schlechteste, da er eine zyklische Abhängigkeit zwischen der DB-Klasse und der Student -Klasse erzeugt.

Wenn Sie also kein Spielzeugprogramm schreiben möchten, verwenden Sie keines davon. Verwenden Sie stattdessen eine andere Klasse wie StudentRepository, um eine API zum Laden und Speichern bereitzustellen, vorausgesetzt, Sie implementieren den CRUD-Code selbst. Sie können auch ein ORM Framework verwenden, das die harte Arbeit für Sie erledigen kann (und das Framework erzwingt normalerweise einige Entscheidungen, bei denen die Operationen Laden und Speichern ausgeführt werden platziert werden müssen).

10
Doc Brown

Es gibt einige Muster, die für die Datenpersistenz verwendet werden können. Es gibt das Muster Arbeitseinheit , es gibt das Muster Repository , es gibt einige zusätzliche Muster, die wie die Remote-Fassade verwendet werden können, und so weiter und so fort.

Die meisten von ihnen haben ihre Fans und ihre Kritiker. Oft geht es darum, das auszuwählen, was am besten zu der Anwendung passt, und dabei zu bleiben (mit all seinen Vor- und Nachteilen, d. H. Nicht beide Muster gleichzeitig zu verwenden ... es sei denn, Sie sind sich wirklich sicher).

Als Randnotiz: In Ihrem Beispiel sollte RetrieveStudent, AddStudent statische Methoden sein (da sie nicht instanzabhängig sind).

Eine andere Möglichkeit, in der Klasse gespeicherte/ladende Methoden zu verwenden, ist:

class Animal{
    public string Name {get; set;}
    public void Save(){...}
    public static Animal Load(string name){....}
    public static string[] GetAllNames(){...} // if you just want to list them
    public static Animal[] GetAllAnimals(){...} // if you actually need to retrieve them all
}

Persönlich würde ich einen solchen Ansatz nur in relativ kleinen Anwendungen verwenden, möglicherweise in Tools für den persönlichen Gebrauch oder wenn ich zuverlässig vorhersagen kann, dass ich keine komplizierteren Anwendungsfälle habe als nur das Speichern oder Laden von Objekten.

Siehe auch persönlich das Muster der Arbeitseinheit. Wenn Sie es kennenlernen, ist es sowohl in kleinen als auch in großen Fällen wirklich gut. Und es wird von vielen Frameworks/APIs unterstützt, um beispielsweise EntityFramework oder RavenDB zu nennen.

3
Gerino

Wenn es sich um eine sehr einfache App handelt, bei der das Objekt mehr oder weniger an den Datenspeicher gebunden ist und umgekehrt (d. H. Als Eigenschaft des Datenspeichers betrachtet werden kann), ist es möglicherweise sinnvoll, eine .save () -Methode für diese Klasse zu verwenden.

Aber ich denke, das wäre ziemlich außergewöhnlich.

Vielmehr ist es normalerweise besser, die Klasse ihre Daten und ihre Funktionalität verwalten zu lassen (wie ein guter Bürger OO Bürger)) und den Persistenzmechanismus an eine andere Klasse oder eine Gruppe von Klassen zu externalisieren.

Die andere Option besteht darin, ein Persistenz-Framework zu verwenden, das die Persistenz deklarativ definiert (wie bei Anmerkungen), die Persistenz jedoch weiterhin externalisiert.

1
Rob