Ich suche Ratschläge zum Design meines Codes.
Ich habe mehrere Klassen, jede repräsentiert einen Dateityp, zB: MediaImageFile, MediaAudioFile und generische (und auch Basisklasse) MediaGenericFile.
Jede Datei hat zwei Varianten: Master und Version, also habe ich diese Klassen erstellt, um ihr spezifisches Verhalten zu definieren. BEARBEITEN: Version stellt die geänderte / beschnittene / abgeschnittene / etc-Variante der Master-Datei dar. Es wird hauptsächlich für Vorschauen verwendet.
BEARBEITEN: Der Grund, warum ich es dynamisch machen möchte ist, dass diese App wiederverwendbar sein soll (es ist Django-App) und daher sollte es einfach sein, andere MediaGenericFile-Unterklassen ohne zu implementieren Ändern des ursprünglichen Codes.
Zunächst sollte der Benutzer in der Lage sein, eigene MediaGenericFile-Unterklassen zu registrieren, ohne den Originalcode zu beeinflussen.
Ob Datei ist Version oder Master ist leicht (eine Regexp) aus dem Dateinamen erkennbar.
%Vor%Master / Version-Klassen verwenden einige Methoden / Eigenschaften von MediaGenericFile, wie Dateiname (Sie müssen den Dateinamen kennen, um eine neue Version zu generieren).
MediaGenericFile erweitert LazyFile, das nur ein faules Dateiobjekt ist.
Jetzt muss ich es zusammenfügen ...
Bevor ich mit der Programmierung der 'versions' -Funktion begann, hatte ich die Factory-Klasse MediaFile, die die entsprechende Dateitypklasse entsprechend der Erweiterung zurückgibt:
%Vor%Die Klassen Master und Version definieren neue Methoden, die Methoden und Attribute von MediaGenericFile usw. verwenden.
Ein Ansatz ist der dynamisch neue Typ, der Master (oder Version) und MediaGenericFile (oder Unterklasse) erbt.
%Vor%Der zweite Ansatz ist die create Methode 'contribute_to_instance' in Master / Version und ruft sie nach dem Erstellen von new_class auf, aber das ist schwieriger, als ich dachte:
%Vor%Dies funktioniert jedoch nicht. Es gibt immer noch Probleme beim Aufruf der Methoden von Master / Version.
Was wäre ein guter Weg, diese Mehrfachvererbung zu implementieren?
Wie heißt das Problem? :) Ich habe versucht, einige Lösungen zu finden, aber ich weiß einfach nicht, wie ich dieses Problem benennen soll.
Vielen Dank im Voraus!
Vergleich und Instanzprüfung wären für meinen Fall kein Problem, denn:
Vergleiche werden trotzdem neu definiert
%Vor%Ich muss nie isinstance (MediaGenericFileVersion, instance) prüfen. Ich verwende isinstance (MediaGenericFile, Instanz) und isinstance (Version, Instanz) und beide funktionieren wie erwartet.
Trotzdem klingt das Erstellen eines neuen Typs pro Instanz für mich als erheblicher Defekt.
Nun, ich könnte beide Variationen dynamisch in der Metaklasse erstellen und sie dann verwenden, etwa wie folgt:
%Vor%Und dann:
%Vor%Schließlich ist das Designmuster eine Fabrikklasse. MediaGenericFile-Unterklassen sind statisch typisiert, Benutzer können ihre eigenen implementieren und registrieren. Master / Version-Varianten werden dynamisch (aus mehreren Mixins zusammengefügt) in der Metaklasse erstellt und im 'Cache' gespeichert, um Gefahren zu vermeiden, die von larsmans erwähnt werden.
Danke allen für ihre Vorschläge. Endlich verstehe ich das Metaklassen-Konzept. Nun, zumindest denke ich, dass ich es verstehe. Drücken Sie den Ursprungs-Master ...
Sie müssen für jede Instanz keine neue Klasse erstellen. Erstellen Sie die neuen Klassen nicht in __new__
und erstellen Sie sie in __metaclass__
. Definieren Sie eine Metaklasse in der Basis oder im base_module. Die beiden "varianten" -Unterklassen können einfach als Klassenattribute ihres entsprechenden Elternelements gespeichert werden, und dann schaut __new__
nur den Dateinamen nach eigenen Regeln an und entscheidet, welche Unterklasse zurückgegeben wird.
Achten Sie auf __new__
, das eine andere als die während des Konstruktoraufrufs "nominierte" Klasse zurückgibt. Möglicherweise müssen Sie Schritte ergreifen, um __init__
von __new__
aufzurufen.
Unterklassen müssen entweder:
import
ed und lassen Sie die Eltern oder das Werk durch eine rekursive Suche nach cls.__subclasses
suchen (dies muss möglicherweise einmal pro Erstellung passieren, aber das ist wahrscheinlich kein Problem für die Dateiverwaltung) entry_points
Typ-Tools, aber das erfordert mehr Aufwand und Koordination durch den Benutzer Ich bin mir nicht sicher, wie dynamisch es sein soll, aber ein "Fabrikmuster" (hier unter Verwendung einer Klassenfabrik) ist ziemlich lesbar und verständlich und kann tun, was Sie wollen. Dies könnte als Basis dienen ... MediaFactory
könnte schlauer sein, und Sie könnten mehrere andere Klassen registrieren, anstatt MediaFactoryMaster
etc ... hart zu codieren.
andere mögliche MediaFactory.make
%Vor% Ich würde sicherlich von dem ersten Ansatz abraten, Klassen in __new__
zu konstruieren. Das Problem dabei ist, dass Sie einen neuen Typ pro Instanz erstellen, was Overhead und Schlimmeres verursacht und dazu führt, dass Typvergleiche fehlschlagen:
Dies verletzt das Prinzip der geringsten Überraschung, denn die Klassen scheinen völlig identisch zu sein:
%Vor% Wenn Sie die Klassen auf Modulebene außerhalb von MediaFile
:
Dann, in MediaFile.__new__
, suchen Sie die gewünschte Klasse nach Namen in classes
. (Alternativ können Sie die neu erstellten Klassen auf dem Modul statt in dict
setzen.)
Wie kommt es, dass Sie keine Vererbung verwenden, aber mit __new__
?
Es ist nicht klar, warum du das tust. Ich denke, hier ist ein komischer Code-Geruch. Ich würde weniger Klassen mit einer konsistenten Schnittstelle ( Duck-Typing ) als ein Dutzend Klassen empfehlen und isinstance
überprüft den gesamten Code, damit alles funktioniert.
Vielleicht können Sie Ihre Frage mit dem, was Sie in Ihrem Code tun möchten aktualisieren und Leute können helfen, entweder das echte Muster zu identifizieren oder eine idiomatische Lösung vorschlagen.
Die OOD-Frage, die Sie stellen sollten, lautet: "Teilen die verschiedenen Klassen meiner vorgeschlagenen Vererbung überhaupt Eigenschaften ?
? Der Zweck der Vererbung ist es, gemeinsame Daten oder Methoden zu teilen, die die Instanzen natürlich gemeinsam haben. Abgesehen von beiden Dateien, was haben Bilddateien und Audiodateien gemeinsam? Wenn Sie Ihre Metaphern wirklich strecken wollen, könnten Sie vielleicht AudioFile.view()
haben, was zum Beispiel eine Visualisierung der Leistungsspektren der Audiodaten darstellen könnte, aber ImageFile.listen()
macht noch weniger Sinn.
Ich denke, dass Ihre Frage dieses sprachunabhängige konzeptuelle Problem zugunsten der Python-abhängigen Mechanik einer Objektfabrik behandelt. Ich denke nicht, dass Sie hier einen ordnungsgemäßen Vererbungsfall haben, oder Sie haben nicht erklärt, welche gemeinsamen Merkmale Ihre Media-Objekte teilen müssen.
Tags und Links python design oop multiple-inheritance