Ich konnte leider nicht so leicht erkennen, inwiefern sich die verschiedenen Dokumente unterscheiden.
Die start() Methode scheint immer das gleiche zu machen, ebenso readDocument().
In start() scheint dabei jeweils eine vom Dokumenttyp zugehörige Mask Instanz verwendet zu werden, die dann in ihren jeweiligen fill() Methoden unterschiedliche Sachen machen.
Für diesen Fall sehe das dann in etwa so aus
Code:
class Mask
{
public:
virtual ~Mask() {}
virtual void fill( QString file_content, QFileInfo fileinfo ) = 0;
};
Code:
class BookMask : public Mask
{
public:
// Implementierung von BookMask::fill()
void fill( QString file_content, QFileInfo fileinfo );
};
class RecipeMask : public Mask
{
public:
// Implementierung von RecipeMask::fill()
void fill( QString file_content, QFileInfo fileinfo );
};
Code:
class Document
{
public:
virtual ~Document() { delete mask; }
// die gemeinsame Implementierung
void start();
protected:
explicit Document(Mask *mask) : mask(mask) {}
Mask *mask;
};
Code:
class BookDocument : public Document
{
public:
BookDocument() : Document(new BookMask) {}
};
class RecipeDocument : public Document
{
public:
RecipeDocument() : Document(new RecipeMask) {}
};
Also die Implementierung von start() ist für alle Document Klassen identisch, den Unterschied macht die jeweilige Mask Klasse bzw dessen fill() Methode.
Das hier ist eine Art Basisfall, d.h. es gibt keine Gemeinsamkeiten von BookMask::fill() und RecipeMask::fill(), die Methode Mask::fill() ist daher "pure virtual" (virtual vorne und "= 0" am Ende).
Wenn der aufrufende Code das hier ist:
Code:
Document *document = new BookDocument();
document->start(....);
dann wird in mask->fill() aufgerufen. Nachdem "this" in diesem Fall ein BookDocument ist, ist "mask" ein BookMask, d.h. BookMask::fill() wird aufgerufen.
In deinem Code gibt es allerdings Gemeinsamkeiten, d.h. es gibt potentiell Möglichkeiten duplizierten Code zu vermeiden.
Dafür gibt es mehrere Ansätze, die oft auch kombiniert werden können.
Beispiel: in den beiden fill() Methoden, die ich mir angesehen habe, sind "check version" und "get color" identisch.
Man könnte die also als Methoden in Mask (Basisklasse) hinzufügen
Code:
class Mask
{
protected:
QString version;
QColor color_cmb;
void getVersion(QString file_content);
void getColor(QString file_content);
};
Die fill() Methoden von BookMask und RecipeMask könnten dann so etwas machen
Code:
void BookMask::fill(QString file_content, QFileInfo fileinfo)
{
getVersion();
// get name
getColor();
// get book specific data
}
Hier ist "get name" innerhalb des ansich gleichen Teils. Wenn die Reihenfolge egal ist, kann man dass natürlich in den "specific" Teil ziehen und sowas machen
Code:
class Mask
{
public:
virtual void fill( QString file_content, QFileInfo fileinfo )
{
getVersion();
getColor();
// usw
}
};
class BookMask : public Mask
{
public:
virtual void fill( QString file_content, QFileInfo fileinfo )
{
// get common data
Mask::fill(file_content, fileinfo);
// get book specific data
}
};
Wieder unter Annahme des aufrufenden Codes von oben: Document::start() ruft mask->fill() auf. "mask" ist vom Typ BookMask, also wird BookMask::fill() ausgeführt. Das leitet erstmal auf Mask::fill() weiter und macht dann seinen Rest.
Wenn das nicht reicht, also wenn z.B. die Reihenfolge der Leseoperationen wichtig ist, z.B. "get name" zwar typspezifisch ist aber immer zwischen "get version" und "get color" gemacht werden muss, dann kann man das so lösen
Code:
class Mask
{
public:
virtual void fill( QString file_content, QFileInfo fileinfo )
{
getVersion();
getName();
getColor();
// usw
}
protected:
virtual void getName() = 0;
};
class BookMask : public Mask
{
public:
virtual void fill( QString file_content, QFileInfo fileinfo )
{
// get common data
Mask::fill(file_content, fileinfo);
// get book specific data
protected:
void getName()
{
// get name in book specific way
}
};
In diesem Fall wird in Mask::fill() der Aufruf von getName() wieder zurück nach BookMask::getName() geleitet und danach mit dem gemeinsamen Code ("get version") weiter gemacht.
Ciao,
_
P.S.: ein paar generelle Anmerkungen:
* QFile kann am Stack, also ohne new, erzeugt werden wenn es nur innerhalb einer Methode benutzte wird. Das stellt sicher, dass das Objekt auch wieder zerstört wird, Derzeit hast du einige Leaks, z.b. buf_file in RecipeDocument::readDocument(), wenn das Öffnen fehlschlägt.
* Wenn es über mehrere Methoden hinweg genutzt wird, sollte es zumindest im Destructor der Klasse gelöscht werden.
* qDebug() << Q_FUNC_INFO << ....;
Lesezeichen