2010-11-19 7 views
1

Ich habe keine Probleme mit Code seit meinem letzten Problem mit der Kovarianz der Schnittstelle. Heute habe ich eine andere Annäherung an die OLGAtherer Architektur genommen und ich fand großes (für mich) Hindernis. Ich hoffe, dass seine großen nur für mich und ich werde finden hier beantworten :) OK, bitte check this out:Wie auf generische abstrakte Klasse zeigen?

Ich habe abstrakte allgemeine Klasse:

abstract class Repository<T> where T : Entity 

diese Klasse enthält Unterschriften von vier CRUD Methoden (add , einfügen usw.) und zwei geschützte Felder. Jedes Repository, das ich erstellen möchte, muss von dieser Oberklasse erben. Ich habe Repositories wie zum Beispiel:

class BookRepository : Repository<Book> 

Jetzt Klasse DB Ich habe, die für den Betrieb auf DB-Datei verantwortlich ist. Und da ist mein Problem. bei dieser Methode in DB-Klasse platziert aussehen:

void Add(List<Entity> enitites, Type entityType) 
    { 
     Repository<entityType> repo = EntitiesFactory(entityType); 
     repo.Add(entities); 
    } 

Ich weiß, dass oben genannte Verfahren wird nicht funktionieren, aber das ist mein Problem visualisieren (hoffentlich) - Ich möchte dynamisch Repository des angegebenen Typs schaffen, aber ich habe keine Ahnung wie man das macht. Dies war immer mein Haupt-OOP-Problem - ich konnte die Vererbung (oder die Implementierung von Schnittstellen) codieren, aber ich konnte diese geerbten Klassen nicht verwenden. Bitte klären Sie dies mit mir. Vielen Dank im Voraus.

Paweł


benutzte ich Hinweise, die Ihnen zur Verfügung gestellt, und das ist, was ich habe jetzt:

public void Add<T>(List<T> entities, string repoName) where T : Entity 
{ 
    Repository<T> repo = RepoFactory<T>(repoName, typeof(T)); 
    repo.Add(entities); 
} 

private Repository<T> RepoFactory<T>(string repoName, Type t) where T : Entity 
{ 
    if (t == typeof(Book)) 
    { 
    Repository<T> repo = (Repository<T>)((object)(new BookRepository(this.ConnectionString, repoName))); 
    } 

    return null; 

}

RepoFactory ist jetzt in DB-Klasse (das heißt, durch die Weg, eine Art Brücke hier) - es sollte wahrscheinlich woanders hin verschoben werden, aber es ist kein Hauptproblem hier.

Erstens, ich weiß nicht, ob RepoFactory Körper in der richtigen Weise implementiert ist - ich denke nicht.

Zweitens - ich nehme an, dass ich DB-Methoden von einer anderen Klasse (sagen wir mal - WindowsForm, der Einfachheit halber) aufrufen wird. Ich werde Add mit dem Parameter T abhängig von der Wahl des Benutzers aufrufen. Dies ist Situation, dass ich Problem habe und behebe es vorübergehend, weil jetzt DB OK ist, aber wenn ich WindowsForm Code implementieren müsste, werde ich es ein anderes Mal treffen (denke ich) - in der Zukunft werde ich versuchen, Antwort auf herauszufinden die gleiche Frage, aber auf der höheren Ebene (über DB) - Ich hoffe, Sie verstehen mich ... Ich meine im Grunde, dass ich nicht wissen, wie Add-Methode dynamisch aufrufen, weil T abhängig von der Wahl des Benutzers sein wird (OLGAtherer hat Repository-Manager zu sein, der Bücher und andere Sammlungen unterstützt). Und wenn der Benutzer versucht, mit seiner Büchersammlung zu arbeiten, muss ich die Methode Add() aufrufen. Wenn mit der Comics-Sammlung, Hinzufügen(). Ich möchte die Klasse nicht für jede Art von Sammlung oben schreiben, sondern einen Aufruf von Add verwenden, um dies zu tun.

Wenn du verstehst, was ich meine, du bist wirklich gut :) Mein Englisch saugt, aber ich arbeite daran. Vielen Dank für die vorherigen Antworten und danke im Voraus für weitere. Paweł

+1

Hmmm, ich denke du versuchst das Rad neu zu erfinden. Warum würden Sie Ihr eigenes ORM schreiben, wenn es bereits viele gut entwickelte Alternativen wie NHibernate und Linq2Sql gibt? – Juliet

+0

'DB' klingt wie ein Gott-Objekt und' EntitiesFactory' klingt wie ein Service-Locator. Sie stellen sich auf ein nicht zu bewältigendes, nicht testbares Desaster ein. – jason

+0

Hallo, ich weiß, dass dies vielleicht keine gute Idee ist - ich lerne immer noch und ich weiß, dass das Mastering von OOP Jahre dauern wird. Aber wenn Sie sich meinen Quellcode von Sourceforge ansehen würden, würde ich annehmen, dass Sie die Architektur akzeptieren würden, die ich bisher erstellt habe. Danke für die Antwort trotzdem. – skrzeczowas

Antwort

7

Ich bin mir nicht ganz sicher, was Sie wollen. Wird das tun?

Auch schlage ich vor, dass Sie so flexibel wie möglich mit Eingabeparametern, z. Verwenden Sie IEnumerable<T> anstelle von List<T> für diese Methode und auch in der Repository<T>.Add() Methode. Möglicherweise möchten Sie eine lazy-evaluated-Abfrage übergeben oder mehrere LINQ-Methoden miteinander verketten.

+0

+1 Genau das, was ich beantworten wollte. – Sorax

+0

WOW. Jedes Mal, wenn ich keine Ahnung habe, was zu tun ist und ich nirgends eine Antwort finden kann, weiß ich, dass ich hier posten kann und ich werde sicherlich die Antwort bekommen! Danke dafür und für diese nützlichen Hinweise zum Thema Abhängigkeiten. Ich möchte Sie bitten, meinen neuen Beitrag unten zu lesen - es gibt den nächsten Teil dieser Frage :) Mit freundlichen Grüßen, Paweł – skrzeczowas

3

Sie können die Methode Add generisch machen.

void Add<T>(List<T> enitites) 
{ 
    Repository<T> repo = EntitiesFactory(typeof(T)); 
    repo.Add(entities); 
} 
+0

Ja, das ist es :) – skrzeczowas

2

Sie können es machen sicheren Typ von Ihrem Objekt hiearchy mit einer weiteren Schicht Indirektionsebene wie folgt zu ändern:

public abstract class EntityCollection<T> : List<T> 
    where T : Entity 
{ 
    public abstract Repository<T> GetRepository(); 
} 

public class BookCollection : EntityCollection<Book> 
{ 
    public override Repository<Book> GetRepository() 
    { 
     return BookRepository(); 
    } 
} 

So, jetzt können Sie Ihre DB-Klasse wie folgt ändern:

public void Add<T>(EntityCollection<T> entities) 
{ 
    Repository<T> repo = entities.GetRepository(); 
    repo.Add(entities); 
} 

So können Sie jetzt eine Instanz BookCollection in Ihre Add Methode übergeben und es wird in einer 100% typsicheren, transparenten Weise arbeiten.

+0

Ich weiß nicht, ob das genau die Antwort ist, die Sie suchen, aber es ist besser zu behalten es ist sicher, als sich auf Güsse und Typprüfungen stark zu verlassen. Wenn Sie einen generischen Typ-Parameter einschalten müssen, machen Sie etwas falsch. – Juliet

+0

Julia, was du sagst ist sicherlich richtig, aber eigentlich habe ich die Frage oben gestellt, weil ich nicht weiß, wie ich nicht wechseln soll. Es wäre schön, wenn du mir sagen würdest, was du nicht tun sollst. – skrzeczowas

2

Um die Antworten aller anderen hinzuzufügen, sollten Sie sich auch das Design der Inversion of Control (IoC) ansehen. Es kann Ihr Leben in der zukünftigen Arbeit vereinfachen.

Mit der Abhängigkeitsinjektion, die IoC Ihnen bietet, können Sie die Verwendung der EntitiesFactory beispielsweise erheblich vereinfachen.

Ich verwende im Moment StructureMap um IoC zu implementieren und es funktioniert gut für mich.

Hier ist Martin Fowler's Seite auf IoC, und Wikipedia's, um loszulegen.

+0

Vielen Dank für diese Antwort! Ich bin sehr froh, dass ich hier so viele nützliche Informationen bekomme. – skrzeczowas

1

Was auch immer Sie zurückgeben in EntitiesFactory() ist, was Sie verwenden müssen. Das Problem ist also wirklich mit Code, den Sie nicht gezeigt haben. Zeigen Sie den Code für EntitiesFactory() und wir bekommen eine bessere Vorstellung davon, was Sie erreichen möchten.

HINWEIS: Sie verstehen, dass Sie Rückgabetypen (leider) nicht überladen können.

+0

Leider Code, den ich oben in Add-Methode schrieb, ist eine Art von "Pseudo-Code". Ich meine, dass das ist, wie ich gerne arbeiten würde :) Bitte lesen Sie den Post unten.Danke für die Antwort trotzdem. – skrzeczowas