Designidee gesucht (einfach)



  • Die Idee vom Pumuckl kann man noch etwas verfeinern.

    Wiederholt std::remove_if aufzurufen ist einigermassen ineffizient, dann lieber ein std::remove_if mit einer Bedingung aufrufen, die über alle Filter iteriert.

    Zudem sehe ich keinen Sinn darin, Strings zu übergeben, die in Funktionen konvertiert werden (ohne Fehlerbehandlung). Da übergibt man lieber gleich eine Liste von den Funktionen. Spart man sich nebenbei auch die Map.

    Als letzte Kleinigkeit (wobei das über den Pseudocode hinausgeht) könnte man auch noch zwei Iteratoren anstelle des ersten Vektors und zwei weitere anstelle des zweiten Vektors. Dann kann man den Aufruf auch ohne C++11 in zwei Zeilen erledigen -- mit einem statischen Array.



  • Ich würde einfach nen Funktor übergeben (einen!).
    Die Veroderung verschiedener Bedingungen kann man ja leicht ausserhalb zusammenbasteln.

    Wenn das zu wenig nach Java riecht kann man natürlich auch PredicateChecker und MultiPredicateChecker Klassen o.ä. machen 🙂



  • Hier könnte auch das Specification pattern passen:

    http://en.wikipedia.org/wiki/Specification_pattern



  • hustbaer schrieb:

    Ich würde einfach nen Funktor übergeben (einen!).
    Die Veroderung verschiedener Bedingungen kann man ja leicht ausserhalb zusammenbasteln.

    Nur ein Funktor? Meinst du, ganz auf die Funktion verzichten und std::remove_if verwenden?

    Es geht hier ja genau darum, die Verunderung zu vereinfachen.

    Mechanics schrieb:

    Specification pattern

    Jetzt riechts eindeutig nach Java.



  • Mechanics schrieb:

    http://en.wikipedia.org/wiki/Specification_pattern

    I pack it not.



  • meistereder schrieb:

    Nur ein Funktor? Meinst du, ganz auf die Funktion verzichten und std::remove_if verwenden?

    Es geht hier ja genau darum, die Verunderung zu vereinfachen.

    Upps, meinte natürlich auch verundern nicht verodern!

    Ich meinte ... die Teile die mit einem "Classifier" arbeiten könnten einfach einen Funktor annehmen. Entweder gleich per Tempalte oder halt als std::function<bool(Thing const&)> . In pumuckls Beispiel also die applyFilters Funktion (die dann nur mehr applyFilter heissen würde oder gleich ganz wegfallen tun täte).

    Und dann kann man getrennt davon einen "Verunderer" schreiben. Ist ja nicht schwer, und Möglichkeiten gibt's viele. Wie das Interface idealerweise aussieht kommt wohl drauf an wie und wo du die Daten herbekommst.

    z.B.

    class Thing;
    
    class Verunderer : public std::unary_function<Thing, bool> // verquere Logik, Result als letztes Argument, wer macht denn sowas!?!
    {
    public:
        typedef std::function<bool(Thing const&)> Predicate;
    
        bool operator() (Thing const& t)
        {
            for (auto& pred : m_predicates)
                if (!pred(t))
                    return false;
            return true;
        }
    
        void AddPredicate(Predicate const& p)
        {
            m_predicates.push_back(p);
        }
    
    private:
        std::vector<Predicate> m_predicates;
    };
    

    Oder auch eine der 1000 anderen Varianten.

    Mechanics schrieb:

    Jetzt riechts eindeutig nach Java.

    Hihi, ja, im Endeffekt läufts aber darauf hinaus schätze ich. Also wenn du Logik (Code) als Daten abspeichern und zur Laufzeit interpretieren willst.



  • Es geht hier ja genau darum, die Verunderung zu vereinfachen.

    Nach deinem Beispiel ist die Bedingung sehr anwendungsspezifisch. Klar geht der "Java"-Weg, aber sinnvoll muss er in deinem Beispiel nicht sein.

    Problem: Je nach Anwendung kann sich die Anzahl der zu prüfenden Intervalle ändern.

    Dann wird fuer jeden Anwendungsfall ein eigener Funktor geschrieben. Darum kommst du so oder so nicht herum.

    // verquere Logik, Result als letztes Argument, wer macht denn sowas!?!
    

    Beispielsweise die Mathematiker: f: R -> R, in Prolog ist idealerweise die Ungebundene(n) Variable(n) weit am Ende zu setzen, dann kommt der Index besser klar.



  • hustbaer schrieb:

    Mechanics schrieb:

    Jetzt riechts eindeutig nach Java.

    Hihi, ja, im Endeffekt läufts aber darauf hinaus schätze ich. Also wenn du Logik (Code) als Daten abspeichern und zur Laufzeit interpretieren willst.

    Das hab ich nicht geschrieben 😉 Aber ja, es riecht nach Java, zumindest die Beispiele auf Wikipedia. Das Konzept ist aber gleich. Ob man das jetzt mit Functoren oder mit Interfaces umsetzt, finde ich relativ nebensächlich, das ist dann auch Geschmackssache. Was meinst du mit "Code als Daten speichern"? Ich seh jetzt gar keinen so großen Unterschied zu deinem Verunderer. Nur kann man dadrüber noch steuern, ob man jetzt verunden oder verodern will 😉



  • hustbaer schrieb:

    class Verunderer : public std::unary_function<Thing, bool> // verquere Logik, Result als letztes Argument, wer macht denn sowas!?!
    

    std::unary_function verwendet in C++11 eh keiner mehr, das ist nämlich deprecated -- zusammen mit vielen anderen Antiquititäten aus <functional> .



  • knivil schrieb:

    // verquere Logik, Result als letztes Argument, wer macht denn sowas!?!
    

    Beispielsweise die Mathematiker: f: R -> R, in Prolog ist idealerweise die Ungebundene(n) Variable(n) weit am Ende zu setzen, dann kommt der Index besser klar.

    Jo.
    Logik war auch das falsche Wort, logisch ist es eh. Macht ne schöne temporale bzw. kausale Ordnung. Erstmal braucht man die Parameter, dann kann man das Ergebnis errechnen.
    Wirkt nur in einer Sprache wo es immer andersrum geschrieben wird etwas out-of-place. (Trailing return types gab's damals ja noch nicht.)



  • Mechanics schrieb:

    Das hab ich nicht geschrieben (...)
    Was meinst du mit "Code als Daten speichern"?

    Naja das ganze "data driven blubbs" läuft oft darauf hinaus dass man etwas was ich einfach mal "Code" nenne mit irgendwelchen "beschreibenden" (hust) Datenstrukturen nachbildet.
    Irgendwann ist dann der Punkt erreicht wo es einfacher und leserlicher würde wenn man eben einfach Code hinschreibt. Komplexe Entscheidungsbäume oder Regexen in riesen unübersichtlichen XML Files oder Datenbanken...

    <blubbsiDecision>
      <xyz:or>
        <xyz:and>
          <xyz:greater>
            <xyz:parameter name="lhs">
               <xyz:globalPropertyFetcher propertyName="globals.businessLogic.ichBinAuchNochDa.maximaleWurstbrotdicke" />
            </xyz:parameter>
            <xyz:parameter name="rhs">
               <xyz:entityPropertyFetcher this="{this}" propertyName="wurstbrotdicke" />
            </xyz:parameter>
          </xyz:greater>
          <!-- ... -->
        </xyz:and>
        <!-- ... -->
      </xyz:or>
    </blubbsiDecision>
    

    ... *schauder*
    (Wobei mir klar ist dass es manchmal kaum anders geht, aber naja, davon lass ich mich nicht vom sudern abhalten, wäre ja noch schöner *g*)

    Und wie ich darauf komme: so wie du es schreibst klingt es einfach danach als ob die Bedingung "Data-driven" zusammengestoppelt werden soll.

    Weil wenn nicht, dann frage ich mich echt was man da im Zeitalter von Lambdas noch grossartig vereinfachen soll? Dann lass den unnötigen Verunderer einfach weg und schreib an der Stelle wo du es brauchst einfach schnell ein Lambda.
    Falls du (wie ich) den C++03 Klotz am Bein hast und nicht wegbekommst verstehe ich es schon eher. Boost.Lambda ist ja wirklich alles andere als schön.

    Ich seh jetzt gar keinen so großen Unterschied zu deinem Verunderer. Nur kann man dadrüber noch steuern, ob man jetzt verunden oder verodern will 😉

    Nö, gibt eh keinen grossen Unterschied, läuft im Prinzip auf das selbe raus.
    Ist aber das was du haben wolltest wenn ich dich richtig verstanden habe ...?


Anmelden zum Antworten