Design
-
Hallo, wie findet ihr den Prototypen? Richtet eure Aufmerksamkeit am besten auf main (ganz unten)
Sprachunterstützung ist nur Zusatz.
Leute, lasste es Kritik hageln!PS ist für MSVC "optimiert" (Templates...)
#include <iostream> #include <string> #include <locale> #include <map> #include <sstream> using namespace std; string umlaut (const std::string &s) { //nicht wichtig, nicht beachten. string tmp; tmp.reserve(s.size()); try { for (unsigned int i = 0; i < s.size(); ++i) { if (s.at(i) == ':') { tmp.pop_back(); char c = s.at(i-1); if (c == 'u') tmp.push_back(char(129)); else if (c == 'o') tmp.push_back(char(148)); else if (c == 'a') tmp.push_back(char(132)); else if (c == 'A') tmp.push_back(char(142)); else if (c == 'O') tmp.push_back(char(153)); else if (c == 'U') tmp.push_back(char(154)); else tmp += c, tmp += ':'; continue; } tmp.push_back(s[i]); } } catch (...) {} return tmp; } class name { //Wrapper um locales zu ermöglichen string rep; public: name (const string &s) : rep(s) {} name (const name &n) : rep(n.rep) {} name (const char *c) : rep(c) {} const name &operator = (const name &n) { if (this != &n) rep = n.rep; return *this; } operator string () const { return rep; } }; class nameIO : public locale::facet { //name-facette mutable map<string, string> Mappe; //pfui struct sec_eq { const string &x; sec_eq (const string &s) : x(s) {} bool operator () (const pair<string, string> &p) { return p.second == x; } }; protected: void add (const string &s1, const string &s2) const { Mappe[s1] = s2; } public: nameIO (int i = 0) : locale::facet(i) {} virtual ~nameIO () {} static locale::id id; virtual string toString (name &n) const { if (Mappe[string(n)] == "") return string(n); else return Mappe[string(n)]; } //sinn und benutzung der eingabe Funktion noch nicht überlegt virtual bool fromString (const string &s, name &n) const { if (Mappe[s] == "") return (n = Mappe[s], true); else return false; } }; locale::id nameIO::id; ostream &operator << (ostream &out, name n) { const locale &loc = out.getloc(); if (has_facet<nameIO>(loc)) { stringstream tmp(n); string buf; while (tmp>>buf) out << use_facet<nameIO>(loc).toString (name(buf)); return out; } return out << string(n); } //Wie gesagt, noch recht unsinnig istream &operator >> (istream &in, name &n) { const locale &loc = in.getloc(); if (has_facet<nameIO>(loc)) { const nameIO &nIO = use_facet<nameIO>(loc); string buf; if (!(in>>buf) && nIO.fromString(buf, n)) in.setstate(ios_base::failbit); return in; } string buf; in >> buf; n = buf; return in; } //Es folgen drei verschiedene Implementationen für verschiedene Sprachen class deutsch : public nameIO { public: deutsch () { add("Sirup", "Himbeersirup"); add("Coke", "Cola"); add("Heiss", "heisse/r/s "); add("MitEis", ", mit Eis"); add("Verduennt", umlaut("verdu:nnte/r/s ")); add("MitZucker", ", gezuckert"); add("MitZitrone", ", mit einer Zitrone"); } }; class englisch : public nameIO { public: englisch () { add("Tee", "tea"); add("Sirup", "strawberry-sirup"); add("Heiss", "hot "); add("Verduennt", "thinned "); add("MitZucker", ", with sugar"); add("MitZitrone", ", with a lemon"); add("MitEis", ", cool"); } }; class slowenisch : public nameIO { public: slowenisch () { add("Tee", "cai"); add("Sirup", "sirup"); add("Coke", "kola"); add("Heiss", "topli/a/o "); add("Verduennt", "razredceni/a/o "); add("MitZucker", ", s sladkorjem"); add("MitZitrone", ", s citrono"); add("MitEis", ", mrzli/a/o"); } }; //Nur aus Faulheit template <class T> void set_sprache (const T &dummy) { //dummy für den M$chrott locale loc(locale(), new T); cout.imbue(loc); cin.imbue(loc); } //Pure Virtualle Basisklasse für AlkoholfreiesGetraenk und AlkoholischesGetraenk class Getraenk { public: virtual name getName () = 0; virtual float getPreis (float pro_liter) = 0; virtual float getEinheit () = 0; virtual ~Getraenk() {} }; //Decorator für Alkoholfreies und AlkoholischesGetraenk class GetraenkDecorator : public Getraenk { Getraenk *next; protected: Getraenk *getNext () { return next; } GetraenkDecorator (Getraenk *n) : next(n) {} name getName () { return next->getName(); } float getPreis (float pro_liter) { return next->getPreis(pro_liter); } float getEinheit () { return next->getEinheit(); } virtual ~GetraenkDecorator () { delete next; } }; //AlkoholischesGetraenk, ebenfalls pure virtual class AlkoholischesGetraenk : public Getraenk { public: virtual float getAlkoholanteil () = 0; }; //Decorator für AlkoholischesGetraenk class AlkoholischesGetraenkDecorator : public AlkoholischesGetraenk { AlkoholischesGetraenk *next; protected: AlkoholischesGetraenk *getNext () { return next; } AlkoholischesGetraenkDecorator (AlkoholischesGetraenk *n) : next(n) {} name getName () { return next->getName(); } float getPreis (float pro_liter) { return next->getPreis(pro_liter); } float getEinheit () { return next->getEinheit(); } float getAlkoholanteil () { return next->getAlkoholanteil(); } virtual ~AlkoholischesGetraenkDecorator () { delete next; } }; //AlkoholfreiesGetraenk, hab mir noch keine besonderen Eigenschaften überlegt class AlkoholfreiesGetraenk : public Getraenk {}; //Und der Decorator dafür class AlkoholfreiesGetraenkDecorator : public AlkoholfreiesGetraenk { AlkoholfreiesGetraenk *next; protected: AlkoholfreiesGetraenk *getNext() const { return next; } AlkoholfreiesGetraenkDecorator (AlkoholfreiesGetraenk *n) : next(n) {} name getName () { return next->getName(); } float getPreis (float pro_liter) { return next->getPreis(pro_liter); } float getEinheit () { return next->getEinheit(); } virtual ~AlkoholfreiesGetraenkDecorator () { delete next; } }; //Faulheit siegt :peace: template <class T> class Decorator_traits {}; template <> class Decorator_traits<Getraenk> { typedef GetraenkDecorator Partner; }; template <> class Decorator_traits<AlkoholischesGetraenk> { typedef AlkoholischesGetraenkDecorator Partner; }; template <> class Decorator_traits<AlkoholfreiesGetraenk> { typedef AlkoholfreiesGetraenkDecorator Partner; }; //Seht ihr, Faulheit siegt: //Heiss: Macht Getraenke heiß template <class Base, class Decorator = Decorator_traits<Base>::Partner> class Heiss : public Decorator { public: Heiss (Base *b) : Decorator(b) {} name getName () { return "Heiss " + string(getNext()->getName()); } }; //MitEis: kühlt Getraenke wieder ab template <class Base, class Decorator = Decorator_traits<Base>::Partner> class MitEis : public Decorator { public: MitEis (Base *ptr) : Decorator(ptr) {} name getName () { return string(getNext()->getName()) + umlaut(" MitEis"); } }; //Mit Wasser verdünnt, schmeckt Sirup besser. Aber auch alle //anderen Getraenke kann man verdünnen template <class Base, class Decorator = Decorator_traits<Base>::Partner> class Verduennt : public Decorator { public: Verduennt (Base *b) : Decorator(b) {} name getName () { return umlaut("Verduennt ") + string(getNext()->getName()); } }; //Zucker, denke ich, passt nur zu AlkoholfreienGetraenken (pfui, Bacardi) class MitZucker : public AlkoholfreiesGetraenkDecorator { public: MitZucker (AlkoholfreiesGetraenk *g) : AlkoholfreiesGetraenkDecorator (g) {} name getName () { return string(getNext()->getName()) + " MitZucker"; } float getPreis (float l) { return getNext()->getPreis(l) + 0.05F; } }; //Zitrone, glaub ich, auch class MitZitrone : public AlkoholfreiesGetraenkDecorator { public: MitZitrone (AlkoholfreiesGetraenk *g) : AlkoholfreiesGetraenkDecorator (g) {} name getName () { return string(getNext()->getName()) + " MitZitrone"; } }; //Schon wieder Faulheit? Ja! Sogar 2mal. Sieht dann im Code besser aus. AlkoholfreiesGetraenk *zuckern (AlkoholfreiesGetraenk *ptr) { return new MitZucker (ptr); } AlkoholfreiesGetraenk *mit_zitrone (AlkoholfreiesGetraenk *ptr) { return new MitZitrone (ptr); } //Wenn der Compiler schon (M$chrott halt nur ein bisschen) //die TemplateDingsda herleiten kann //Von der Art gibt's sogar drei. Fällt euch vielleicht auf, dass nur es sie //nur für den allgemeinen GetraenkDecorator gibt (nicht für Alk und NichtAlk, //seht ihr dann unten template <class Base> Base *kochen (Base *ptr) { return new Heiss<Base> (ptr); } template <class Base> Base *kuehlen (Base *ptr) { return new MitEis<Base> (ptr); } template <class Base> Base *verduennen (Base *ptr) { return new Verduennt<Base> (ptr); } //Endlich mal ein richtiges Getränk class Tee : public AlkoholfreiesGetraenk { public: name getName () { return "Tee"; //locales kümmern sich um die landesspezifische Ausgabe } float getPreis (float pro_liter) { return 6.4F * pro_liter; } //Passt der Preis? float getEinheit () { return 0.25F; } //Und die Menge pro Tasse? }; //Coca Cola darf nicht fehlen class Coke : public AlkoholfreiesGetraenk { public: name getName () { return "Coke"; } float getPreis (float pro_liter) { return 10 * pro_liter; } float getEinheit () { return 0.2F; } }; //Billiges Allroundgetränk class Sirup : public AlkoholfreiesGetraenk { public: name getName () { return "Sirup"; }; float getPreis (float pro_liter) { return 5.0F * pro_liter; } float getEinheit () { return 0.25F; } }; //Irgendwoher müssen die Getränke ja herkommen! Faulheit siegt, wie immer //Kleine Factory: class Lager { public: static AlkoholfreiesGetraenk *nimmAlkoholfreiesGetraenk(const string &name) { if (name == "Tee") return new Tee; if (name == "Coke") return new Coke; if (name == "Sirup") return new Sirup; return 0; } }; //Endlich, die nette Hauptfunktion int main () { cout << "Welche Sprache / Which Language ?\n"; do { //"Gescheite" Sprachauswahl ist es zwar nicht, Sprache aber im //Moment noch 2.rangig string sprache; cin >> sprache; cin.clear(); cin.ignore(cin.rdbuf()->in_avail()); if (sprache == "Deutsch" || sprache == "German") { set_sprache (deutsch()); break; } else if (sprache == "Englisch" || sprache == "English") { set_sprache (englisch()); break; } else if (sprache == "Slowenisch") { set_sprache (slowenisch()); break; } cout << umlaut("Falsche Eingabe / Incorrect input\nMo:glicherweise ist die gewu:nschte Sprache nicht installiert / Maybe the language you wanted isn't installed\nBitte Eingabe wiederholen / Please repeat your input\n"); } while (1); cout << '\n'; //Teste das Design aus: const int size = 3; Getraenk *glas[size]; //Hätte genauso AlkoholfreiesGetraenk sein können //Hab mir ja noch kein AlkoholischesGetraenk gemacht //Folgendes sieht doch nett aus, oder? glas[0] = zuckern( kochen(Lager::nimmAlkoholfreiesGetraenk("Tee")) ); glas[1] = mit_zitrone ( kuehlen(Lager::nimmAlkoholfreiesGetraenk("Coke")) ); glas[2] = kuehlen( verduennen(Lager::nimmAlkoholfreiesGetraenk("Sirup")) ); //Alle ausgeben for (int i = 0; i < size; ++i) { cout << glas[i]->getName() << ": " << glas[i]->getPreis(glas[i]->getEinheit()) << " Euro" << endl; delete glas[i]; //Was nicht so offensichtlich ist: intern wird ja mit new gearbeitet //Sollte vielleicht lieber mit Handles oder was anderem arbeiten (noch nicht überlegt) } return 0; //M$chrott greetz }
-
string umlaut (const std::string &s) { string tmp; tmp.reserve(s.size()); try { for (unsigned int i = 0; i < s.size(); ++i) { if (s.at(i) == ':') { tmp.pop_back(); char c = s.at(i-1); if (c == 'u') tmp.push_back(char(129)); else if (c == 'o') tmp.push_back(char(148)); else if (c == 'a') tmp.push_back(char(132)); else if (c == 'A') tmp.push_back(char(142)); else if (c == 'O') tmp.push_back(char(153)); else if (c == 'U') tmp.push_back(char(154)); else tmp += c, tmp += ':'; continue; } tmp.push_back(s[i]); } } catch (...) {} return tmp; }
benutzerdefinierte typen die per wert zurück gegeben werden sollten const http://fara.cs.uni-potsdam.de/~kaufmann/?page=GenCppFaqs&faq=constcor#Answ
wieso benutzt du die methode at? sie macht hier eine unnötige bereichsprüfung schneller wäre op[]
der sinn des try{} catch(...){} ist mir auch fremd welchen grund gibt für das?
versuche die schleife mal umzuschreiben, continue raus
statt den if else würde ich ein switch nehmen
außerdem hat die funktion fehler z.b. versuche mal umlaut(":bla") aufzurufen
const string umlaut(std::string s) { for (string::size_type pos = 0; (pos = s.find( ':', pos )) != string::npos; ) { --pos; switch(s[pos]) { case 'u': s.replace( pos, 2, 1, char( 129 ) ); break; case 'o': s.replace( pos, 2, 1, char( 148 ) ); break; case 'a': s.replace( pos, 2, 1, char( 132 ) ); break; case 'A': s.replace( pos, 2, 1, char( 142 ) ); break; case 'O': s.replace( pos, 2, 1, char( 153 ) ); break; case 'U': s.replace( pos, 2, 1, char( 154 ) ); break; } ++pos; } return s; }
hmm aber eine flexieble funktion die mal überall einsetzen kann wäre schöner, eine replace_all habe ich schon nur kann die nur nach einen string suchen und ersetzen
-
Danke, hab die Funktion nur so hingeschlampt und nicht wieder angeschaut.
supi!
-
Original erstellt von <dankeschön>:
Danke, hab die Funktion nur so hingeschlampt und nicht wieder angeschaut.
supi!ist noch nicht zu ende, aber ich mache erstmal pause
so viel kommt da nicht mehr
-
schlaf dich schön aus
-
Übrigens geht es mir nicht um diese kleine Funktion.
Bitte verschieb mich ins Rundum-Forum
-
jetzt bist du da, jetzt verschieb mich. wenn du denkst ich bin nicht der, der den thread erstellt hat, schau dir die IP an.
-
sorry für mein misstrauen
thread verschoben
-
if (sprache == "Deutsch" || sprache == "German") { set_sprache (deutsch()); break; } else if (sprache == "Englisch" || sprache == "English") { set_sprache (englisch()); break; } else if (sprache == "Slowenisch") { set_sprache (slowenisch()); break; }
Hmmm... Ich denke, wenn ein Programm erstmal auf 3 Sprachen ausgelegt ist, dann kommt auch irgendwann eine 4. und eine 5. Sprache dazu. ...und irgendwann ist man dann plötzlich bei der 20. Sprache oder so. Denkst du, das macht dann mit solchen Konstrukten noch Spaß?
Für mich sieht das erstmal schlecht wartbar und schlecht erweiterbar aus. Vielleicht fällt dir da ja noch eine bessere Lösung bezüglich der Sprachen ein.
...das Gleiche gilt natürlich auch für Passagen, wie diese:
class deutsch : public nameIO { public: deutsch () { add("Sirup", "Himbeersirup"); add("Coke", "Cola"); add("Heiss", "heisse/r/s "); add("MitEis", ", mit Eis"); add("Verduennt", umlaut("verdu:nnte/r/s ")); add("MitZucker", ", gezuckert"); add("MitZitrone", ", mit einer Zitrone"); } }; class englisch : public nameIO { public: englisch () { add("Tee", "tea"); add("Sirup", "strawberry-sirup"); add("Heiss", "hot "); add("Verduennt", "thinned "); add("MitZucker", ", with sugar"); add("MitZitrone", ", with a lemon"); add("MitEis", ", cool"); } }; class slowenisch : public nameIO { public: slowenisch () { add("Tee", "cai"); add("Sirup", "sirup"); add("Coke", "kola"); add("Heiss", "topli/a/o "); add("Verduennt", "razredceni/a/o "); add("MitZucker", ", s sladkorjem"); add("MitZitrone", ", s citrono"); add("MitEis", ", mrzli/a/o"); } };
Vielleicht kannst du für jede Sprache eine Datei anlegen, mit Hilfe der du dann bei Programmstart alle sprachspezifischen Variablen, Konstanten etc. setzt.
-
kein Problem. Wie siehts mit den Dekoratoren aus?