C++: Daten wie stark kapseln?

Gast #3788478
Lesenswert?

Ich schreibe grad an nem C++ Programm.
Unter anderem wird da eine "Datenbank" verwaltet, die global irgendwo 
rumfliegt.

Diese Datenbank ist im Prinzip nur ein Vector, der die einzelnen 
Einträge zusammenfasst:
1
std::vector<DatabaseEntry>;

Mir stellt sich nun die Frage ob es sinn macht, diesen globalen Vektor 
zu kapseln, nach dem Motto:
1
class Database
2
{
3
    std::vector<DatabaseEntry>;
4
...
5
//public interface
6
...
7
}

Bin mir da nicht sicher ob es guter Stil ist, den "Anwender" der 
Datensätze direkt an die Implementierung der Datenbank ranzulassen (auch 
wenn der Anwender nur ich selbst bin) oder ob eine Kapselung Sinn macht. 
Nachteil ist eben der Aufwand, ich muss einige Zugriffsfunktionen 
"durchschleifen", z.B. um Einträge hinzuzufügen.
Die Datenbank soll auch mittels boost serialisiert und abgespeichert 
werden. Grade da fände ich es schick, wenn der Anwender nur schreiben 
könnte
1
myDatabase.save();
anstatt selbst die Details der boost::serialization lib kennen zu 
müssen.

Selbiges Problem hab ich eigentlich recht oft, wenn Daten global 
verfügbar sein sollen.
Wie würdet ihr vorgehen?
Persönliche Seite #3788511
Lesenswert?

Ben schrieb:
> Die Datenbank soll auch mittels boost serialisiert und abgespeichert
> werden

Und irgendwan wohl auch gelesen werden und und und ... Eine Kapselung 
macht dir das Leben einfacher, spätestens wenn deine "Datenbank" auch 
mal an verschiedenen Orten Verwendung finden soll, du das 
zugrundeliegende Datenformat oder die speicher/lade logik Ändern 
möchtest.
Gast #3788533
Lesenswert?

Danke, du bestätigst was ich vermutet habe.
Allerdings, ich muss halt erstmal die Zugriffsmethoden auf den internen 
Container nachbilden. Denke aber dass man eh nicht alle braucht, die so 
ein STL Container anbietet.

Zwar leicht offtopic:
Angenommen ich möchte eine Namensliste der Einträge abfragen:
wäre dieser Weg in Ordnung?:
1
std::vector<std::string> getEntryList(void)
2
{
3
    std::vector<std::string> ret;
4
  
5
  for (auto i : entries)
6
      ret.push_back(i.name);
7
  
8
  return ret;
9
}
Dank RVO müsste ich eigentlich wenig Overhead haben, obwohl ich einen 
Vector zurückgebe.
Das Iterieren über die Einträge hätte ich ja ohne extra Kapselung auch.

Grüße,
Ben
#3788606
Lesenswert?

Läubi .. schrieb:
> Ben schrieb:
>> Die Datenbank soll auch mittels boost serialisiert und abgespeichert
>> werden
>
> Und irgendwan wohl auch gelesen werden und und und ... Eine Kapselung
> macht dir das Leben einfacher, spätestens wenn deine "Datenbank" auch
> mal an verschiedenen Orten Verwendung finden soll, du das
> zugrundeliegende Datenformat oder die speicher/lade logik Ändern
> möchtest.

Und die Erfahrung zeigt, dass das früher oder später immer irgendwann 
der Fall sein wird.

D.h. derartige Nicht-Kapselungen sehen zwar auf den ersten Blick nach 
Arbeitsersparnis aus. Aus der Praxis heraus kann ich aber sagen, dass 
das nur auf den ersten Blick so ist. Macht man die Kapselung nicht 
heute, dann macht man sie eben morgen oder nächste Woche. Aber 
irgendwann ist der Punkt erreicht und sei es nur, weil man erkannt hat, 
dass eine derartige Kapselung auch noch ein perfekter Ort wäre, um 
zusätzliche Funktionen unterzubringen wie zb Datenvalidierung, 
Absicherung beim Einfügen von Werten, Laden/Speichern auf Datei, 
Clipboard, XML Generierung, etc. etc.

Der Unterschied: je später man die Kapselung macht, desto mehr Arbeit 
hat man damit, weil ja in der Zwischenzeit auch verwendender Code 
angefallen ist, der jetzt auf die neue Klasse umgestellt werden muss.
#3788611
Lesenswert?

Ben schrieb:

> Dank RVO müsste ich eigentlich wenig Overhead haben, obwohl ich einen
> Vector zurückgebe.

Lass das das Problem des COmpilers sein. Wenn du nett bist, dann 
schreibst du diese kleine Funktion inline ins Header File. Dann hast du 
praktisch gesehen gegenüber deiner Alternativlösung ....

> Das Iterieren über die Einträge hätte ich ja ohne extra Kapselung auch.

... überhaupt keinen Overhead.

Das C++ bzw. die Verwendung von Klassen einen gewaltigen Overhead bei 
gleicher Funktionalität mit sich bringen, ist ein Mythos.
Gast #3790838
Lesenswert?

Ben schrieb:
> Allerdings, ich muss halt erstmal die Zugriffsmethoden auf den internen
> Container nachbilden. Denke aber dass man eh nicht alle braucht, die so
> ein STL Container anbietet.

Du machst natürlich nur die Zugriffsmethoden, die du jetzt gerade 
brauchst - lass das Interface so klein wie möglich, dann ist es 
hinterher einfacher, die dahinterliegende Implementierung zu ändern.
Passe das Interface so gut wie möglich an deine Bedürfnisse an, versuche 
nicht, das Interface von std::vector zu spiegeln.
#3792407
Lesenswert?

Ben schrieb:
> Zwar leicht offtopic:
> Angenommen ich möchte eine Namensliste der Einträge abfragen:
> wäre dieser Weg in Ordnung?:
> std::vector<std::string> getEntryList(void)
> {
>     std::vector<std::string> ret;
>
>   for (auto i : entries)
>       ret.push_back(i.name);
>
>   return ret;
> }
> Dank RVO müsste ich eigentlich wenig Overhead haben, obwohl ich einen
> Vector zurückgebe.

Ja. Ich würde beim Erzeugen des Vektors aber gleich die Kapazität 
passend angeben, da die benötigte Größe ja bekannt ist.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren