Zitat von
Multithread
Entweder weiss es das Objekt, oder eine Statische Factory Klasse.
Etwas anderes, welches ohne grossen Mehraufwand verwendet werden kann, habe Ich bisher noch nicht gesehen.
Dann schaue dir z.B. gängige O/R-Mapper an. z.B. Entity Framework Core:
Code:
public partial class Student
{
public int StudentId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Code:
public partial class SchoolDBContext : DbContext
{
public virtual DbSet<Student> Student { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>(entity =>
{
entity.Property(e => e.StudentId).HasColumnName("StudentID");
entity.Property(e => e.FirstName)
.HasMaxLength(50)
.IsUnicode(false);
entity.Property(e => e.LastName)
.HasMaxLength(50)
.IsUnicode(false);
});
}
}
(N)Hibernate macht dies über eine XML-Datei:
Code:
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2"
assembly = "NHibernateDemoApp" namespace = "NHibernateDemoApp">
<class name = "Student">
<id name = "StudentId">
<generator class = "native"/>
</id>
<property name = "FirstName"/>
<property name = "LastName"/>
</class>
</hibernate-mapping>
Oder über das AddOn FluentNHibernate typsicher über Code:
Code:
public class StudentMap : ClassMap<Student>
{
public StudentMap()
{
Id(x => x.StudentId);
Map(x => x.FirstName)
.Length(50)
.Not.Nullable();
Map(x => x.LastName)
.Length(50)
.Not.Nullable();
}
Ein anderes Beispiel wäre der CsvHelper, um csv-Dateien einzulesen:
Code:
public class StudentMap : ClassMap<Student>
{
public StudentMap()
{
Map(m => m.StudentId).Name("STUDENT_ID");
Map(m => m.FirstName).Name("FIRSTNAME");
Map(m => m.LastName).Name("LASTNAME");
}
}
Die einzige Technik, die ich kenne, wo in den Klassen die Mapping-Informationen stehen, ist der XmlSerializer aus dem .Net-Framework aber will man ernsthaft seine Datenklassen mit (De-)serialisierungsattributen zumüllen?
Wenn eine Klasse Daten und dann noch zusätzlich Informationen über die Persistierung beinhaltet, verstößt die Klasse gegen das Single-Responsibility-Prinzip, da sie zwei Aufgaben beinhaltet.
Die Statische Metode Speicher nicht.
Die Statische Methode geht nur die Liste registrierter 'IPersistentStorage' Instanzen durch, und Prüft mit welcher das Objekt geschrieben /gelesen werden soll.
Es besteht damit auch die Möglichkeit ein Objekt in mehreren Speichern abzulegen (SQL DB und zb. Lucene für eine Effiziente Volltextsuche) und beim Lesen zu entscheiden woher gelesen werden soll.
Die Registrierung erfolgt analog einer DependencyIncection.
Statische Klassen haben kein Konstruktor und somit kannst du auch nicht mit Dependency Injection arbeiten. Das, was du wohl meinst, sind Objekte, die statisch gehalten werden (Singleton-Pattern). Objekte, die statisch gehalten werden und statische Klassen sind zwei unterschiedliche paar Schuhe.
Das bisher grösste Problem, welches Ich gesehen habe, ist das Fehlen eines Designs/einer Linie welcher man beim Programmieren folgen kann.
Das größte Problem, was ich gesehen habe, sind statische Klassen. Ich arbeite hier ein einer Firma, in der vor über 10 Jahren ein O/R-Mapper selbstgebaut wurde und der immer noch verwendet wird. Hier hat man tatsächlich statische Klassen implementiert, um z.B. die Datenbank zu lesen. Die Folge daraus ist nun, dass die komplette Anwendung nicht mit Unittests getestet werden kann und auch kein Multithreading möglich ist, da aufgrund der statischen Klassen zu viele Seiteneffekte entstehen.
Ich würde gerne sehen wie du das Implementieren würdest. In meinem Kopf habe Ich dann doppelten Code, aber vermutlich übersehe Ich nur was.
Mit ISavableObject als BasisInterface für alles was sich Speichern lässt.
Über das Repository- und Unit-of-Work-Pattern, auf das ebenfalls gängige O/R-Mapper basieren. Um bei C# zu bleiben hätte ich dann nachher ein Projekt (eine dll-Datei) mit den Repositories vom Entity Framework, ein weiteres Projekt für NHibernate. etc...
PS: Statische Methoden würde Ich wegen den Unittests nicht verteufeln.
Eben doch. Methoden, die statische Methoden aufrufen, lassen sich nicht isoliert testen. Ein Klassiker unter den Beispielen wäre DateTime.Now(). Habe ich jetzt eine Methode, die DateTime.Now() aufruft, dann erzeugt die Methode immer wieder ein anderes Resultat und lässt sich somit u.U. nicht mehr testen. DateTime.Now() kann ich auch nicht mocken.
Ua. gibt es Funktionen die man gut in einer Statischen Methode abbilden kann, welche nur die Eingabeparameter braucht (z.B. Irgendwelche Berechnungen welche auch mal mehrere 100 Zeilen lang sind)
Wenn man Methoden schreibt, die 100 Zeilen lang sind, dann macht man grundsätzlich was verkehrt. Ich rede hier aus Erfahrung, da ich ständig mit solchen Code zu tun habe.
Sofern man den Cache nach einem Unittest sauber aufräumt (und dafür gibts ja ein Test-Teardown), können diese problemlos mitgetestet werden. Wenn man es nicht macht, dann gibt das die schönsten Effekte
Und das ist der nächste Nachteil von statischen Methoden. Sie können Seiteneffekte hervorrufen, wenn sie nicht stateless sind. Caches, die statisch sind, würde ich immer vermeiden. Das Problem sah ich auch in unserer Anwendung. Da waren auch einige Caches statisch, was zur Folge hatte, ruft man eine Methode zwei Mal auf, gibt die Methode zwei unterschiedliche Ergebnisse zurück, weil der Cache nicht aufgeräumt wurde. Wir haben einizige der Caches instanziierbar gemacht und konnten auch Haufenweise Code rausschmeißen, weil er immer den Status des Caches überprüft hat.
Ein statischer Cache ist auch nicht Multithreading-tauglich. Wenn plötzlich 10 Threads den Cache verwenden wollen, ist das eher hinderlich als nützlich, wenn der Zugriff jedes Mal blockiert werden muss. Da sollte jeder Thread seinen eigenen Cache verwenden. Manchmal kommt man zwar nicht drumherum, dass Threads auf gemeinsame Daten zurückgreifen müssen aber diese Daten würde ich ebenfalls nicht statisch machen.
Statische Klassen haben auch das Problem, dass sie zu einer Müllhalde von Methoden werden, von denen man nicht weiß, wohin damit. Solche Klassen heißen dann oft Helper oder Utils. Solche Klassen habe ich hier auch zu Hauf und beinhalten schon Methoden im dreistelligen Bereich und werden in der gesamten Anwendung verteilt genutzt.
Alles in einem verursachen also statische Klassen nur Probleme.