OOP: soll man jetzt alles in ne Klasse packen oder watt?
-
gurkenesser schrieb:
Klassen sind Funktionsgruppen.
Beispielsweise sämtliche Sachen, die mit Textdateien in einem Textprogramm zu tun haben könnten in eine Klasse (also laden, speichern, löschen, ...)ne, is falsch, das is kein oop. in OOP gibt es keine funktionen. das was du beschrieben hast nennt man auch nicht kapselung.
-
//ungetestet //sollte aber ne flüssige anzeige ergeben void qsort(double a[],int min,int max,SortObserver obs){ if(max-min<=1) return; obs.set(min); int pivot=(min+max)/2; partioniere; qsort(min,pivot,obs); qsort(pivot+1,max,obs); }
-
quote schrieb:
ich erinnere mich auch mit schrecken an
class BubbleSort:public SortAlgorithm...Das hat durchaus seine Berechtigung: Strategy Pattern
volkard schrieb:
pushen statt pollen natürlich.
Prinzipiell funktioniert es dadurch natürlich ganz passabel, problematisch wird es aber durch diese "implizite" Definition. Jeder weitere Sortier-Algorithmus muss sich natürlich dementsprechend analog dazu nach außen verhalten ohne, dass es ihm vorgeschrieben werden kann. Bei einer SortingStrategy könnte man aber z.B: die zu sortierenden Daten kapseln und die Anzahl der Swaps mitzählen.
-
volkard schrieb:
Gregor schrieb:
Wie baut man soetwas also vernünftig auf?
pushen statt pollen natürlich. dann bleibt der algo fast genausoschnell und der optimierer kann wegfetzen, wasimmer er will. beim pollen mußt du erlauben, daß der komplette zustand ausgewertet werden kann, auch schleifenvariablen, die eigenrlich in einem register liegen sollten. und alle lokalen variablen zu attributen zu machen ist auch durchaus unintuitiv.
Wie das innerhalb der Klasse organisiert wird, ist ja mehr oder weniger nebensächlich. Da kann auch eine interne Variable für den Fortschritt drinstehen, die nur ab und zu aktualisiert wird.
Wohin willst Du pushen? ...vor allem, wenn man dann noch davon ausgeht, dass vielleicht mehrere solcher Algorithmen parallel laufen usw. Wird das nicht ziemlich kompliziert, soetwas auf einer anderen Ebene zu regeln?
Gib mal ein Beispiel. Geh mal von einem Algorithmus aus, der jedes Element eines int-Arrays mit 5 multiplizieren soll. In Java würde das wohl mit dr von mir vorgeschlagenen OOP-Variante so aussehen:
public class Multiplier extends IntArrayProcessor { private final int factor; private int currentPosition; private int length; public Multiplier(int factor) { this.factor = factor; reset(); } public void reset() { currentPosition = 0; length = 1; } public float getStatus() { return (float)currentPosition / (float)length; } public void process(int[] array) { length = array.length; for(int i = 0 ; i < array.length ; ++i) { array[i] *= factor; currentPosition = i; } } }
...und irgendein externer Mechanismus setzt das Ding dann in Gang und Frag bei Bedarf ab, wie weit es denn schon ist.
-
volkard schrieb:
//ungetestet //sollte aber ne flüssige anzeige ergeben void qsort(double a[],int min,int max,SortObserver obs){ if(max-min<=1) return; obs.set(min); int pivot=(min+max)/2; partioniere; qsort(min,pivot,obs); qsort(pivot+1,max,obs); }
Ok, das wäre natürlich eine Möglichkeit. ...wobei der Observer offensichtlich auch aus der OOP-Richtung kommt. ...und die Fortschrittsanzeige wäre wohl auch nicht so ganz stabil.
(Was aber wohl bei nem Quicksort eh problematisch wäre.)
-
qwerty` schrieb:
quote schrieb:
ich erinnere mich auch mit schrecken an
class BubbleSort:public SortAlgorithm...Das hat durchaus seine Berechtigung: Strategy Pattern
dann macht man zur not nen tiny wrapper drum. aber gar nicht notwenig, in c++ sind funktionszeiger auch gute objekte, um als strategy benutzt werden zu können.
Jeder weitere Sortier-Algorithmus muss sich natürlich dementsprechend analog dazu nach außen verhalten ohne, dass es ihm vorgeschrieben werden kann.
typprüfung gibts auch für funktionen.
Bei einer SortingStrategy könnte man aber z.B: die zu sortierenden Daten kapseln und die Anzahl der Swaps mitzählen.
das ist ja das einfachste. kannst auch jedem globalen bubblesort nen typ unterschieben, der seine swaps zählt. aber will man sortieralgos ausmessen, nimmt man besser die verbrauchte zeit.
Gregors problem ist viel schwiereiger und praxisnah. man will nen fortschrittsbalken im sortierlauf. ich hab ne lösung angegeben.
-
Gregor schrieb:
Ok, das wäre natürlich eine Möglichkeit. ...wobei der Observer offensichtlich auch aus der OOP-Richtung kommt.
selbstverständlich. ich will ja alles, was sich nicht wehrt, in klassen stecken. und der observer whert sich nicht nur nicht, der bettelt darum.
...und die Fortschrittsanzeige wäre wohl auch nicht so ganz stabil.
(Was aber wohl bei nem Quicksort eh problematisch wäre.)
och, doch schon sehr. diese implemetierung dürfte fast ruckelfrei sein.
aber klar, andere algos ruckeln in der anzeige mehr. bestes beispiel: bubblesort. er geht in der anzeige, den average-case annehmend, sehr langsam vorwärts, dabei immer schneller werdend. aber ah, oh, weh, nach dem dritten (echt lahmen) lauf hat er gemerkt, daß das array fertig sortiert ist (weil nur 3 zufügungen im vokabelbestand vergenommen wurden) und springt unvermittelt auf 100%. das problem ist aber unanhängig von klasse/funktion oder push/poll, dieser algo hat die weitsicht nicht.
-
Gregor schrieb:
Gib mal ein Beispiel. Geh mal von einem Algorithmus aus, der jedes Element eines int-Arrays mit 5 multiplizieren soll.
naja, der algo wie beim sort. und er pusht in nen observer rein.
und jetzt kommt der trick:
willste doch pollen, bist nicht du der observer, sondern du legst nen observer an, in den der algo pusht und du pollst den observer.
begründung: sogar java vereckt prinzipiell mitprivate int currentPosition;
und kann weniger optimieren, als mit lokalen nichtabfragbaren variablen.
-
aber gar nicht notwenig, in c++ sind funktionszeiger auch gute objekte, um als strategy benutzt werden zu können.
Funktionen sind aber ungleich unflexibler als Objekte. Wie wär es z.B mit einem Warnsystem für Hochwasser um ein eher konkretes Beispiel zu liefern?
public class WaterLevelFilter implements Filter { private double criticalWaterLevel; public WaterLevelFilter(double criticalWaterLevel) { // ... } public boolean isCritical(Stream waterFlow) { return waterFlow.getWaterLevel() > criticalWaterLevel; } }
Parameter wie die kritische Höhe des Wasserspiegels lassen sich mit Funktionen als Strategy recht schlecht implementieren.
-
fyi schrieb:
gurkenesser schrieb:
Klassen sind Funktionsgruppen.
Beispielsweise sämtliche Sachen, die mit Textdateien in einem Textprogramm zu tun haben könnten in eine Klasse (also laden, speichern, löschen, ...)ne, is falsch, das is kein oop. in OOP gibt es keine funktionen. das was du beschrieben hast nennt man auch nicht kapselung.
hauptsache kluhg
-
qwerty` schrieb:
aber gar nicht notwenig, in c++ sind funktionszeiger auch gute objekte, um als strategy benutzt werden zu können.
Funktionen sind aber ungleich unflexibler als Objekte.
was soll man da noch sagen?
darf ich mal...template<typename F> void test(F f){ f(17); } double sqr(double x){ return x*x; } struct Sqr{ static double operator(double x){ return x*x; } }; test(sqr); test(Srq());
der test isses hier wurst, ob man ein objekt übergibt oder einen funktionszeiger. und das ist aktueller c++-stil.
hier hat die operatorüberladung (sieghe anderer gelangweilter thread) zum teil für ein pragmatischeres objektverständnis gesorgt.
-
In diesem Fall verhalten sich Funktionspointer und Objekte genauso. Wenn ich mich aber recht erinnere, lassen sich Klassen und Funktionspointer in C++ schlecht mischen. Ausserdem braucht keine OOP-Sprache Funktionspointer, weil sie vollständig durch Objekte ersetzt werden können.
Operatorüberladung ist ein anders Themengebiet.
test(Srq());
Ohne die Klasse Srq zu kennen würde ich hier annehmen das einfach nur ein Srq Objekt erzeugt wird. Das ist das gefährliche an Operatorüberladung.
-
DEvent schrieb:
Ohne die Klasse Srq zu kennen würde ich hier annehmen das einfach nur ein Srq Objekt erzeugt wird. Das ist das gefährliche an Operatorüberladung.
ähm. ohne oder mit solltest du annhemen, daß ein Sqr objekt erzeugt wird.
keine akute gefahr.es geht ja eher um
template<typename F> double test(F f){ double result=0; for(int i=0;i<10;++i) result+=f(i); return result; }
bei f(i) ist die operatorüberladung. für nur einmal-benutzen könnte (und sollte dringlichst) man sich den quark sparen.
-
Stimmt, ja, erst bei f() wird der Operator aufgerufen.
Mein Argument bleibt aber, das wenn man Operatoren überläd, die Operatoren plötzlich ganz andere Wirkung haben könnten als erwartet.
Ausserdem kann man z.B. den = Operator ganz anders interpretieren. Für die einen ist es eine einfache Adressen-Zuweisung, für andere ist es ein deep-copy-Operator.So eine ähnliche Diskussion hatten wir mal in dem Forum, da ging es um den + und += Operator bei String-Klassen.
-
DEvent schrieb:
Stimmt, ja, erst bei f() wird der Operator aufgerufen.
Mein Argument bleibt aber, das wenn man Operatoren überläd, die Operatoren plötzlich ganz andere Wirkung haben könnten als erwartet.
Ausserdem kann man z.B. den = Operator ganz anders interpretieren. Für die einen ist es eine einfache Adressen-Zuweisung, für andere ist es ein deep-copy-Operator.ja, ohne zweifel muss man da bescheiden sein.
mach klassen so, daß sie sich wie ints anfühlen!
zum beispiel der op+ für strings ist bescheuert.
denn "hallo"+"welt"==hallowelt"
aber "welt"+"hallo"!="hallowelt"
und gar "hallowelt"-"hallo" ist undefiniert.
in den frühen zeiten von c++ wurden 2dimensionale arrays immer mit nem op()(int x,int y) ausgestattet. ja sogar listen mit nem op()(int position). das ist natürlich unfug.
mein beipspiel mit dem op() ist da ok, man übergibt eine funktion, die was tun soll (oder ein objekt, das was tun soll) und ruft sagt der funktion/onjekt mit () dann "erfülle deinen zweck, mach, wozu du da bist, führe deinen code aus und berechne". im gegensatz ob reinen funktionen können objekte darüberhinaus noch andere sachen machen, aber im kontext der benutzenden test-funktion ist das objekt nur ein ding, das eine funktion ist. es wäre nicht toll, unterscheiden zu müssen und machmal sqrt(x) und macnhmal sqrt.calc(x) aufrufen zu müssen. ich will ja kein lexikon der wirren apis werden, sundern meinen geist aufsparen können, algorithmen zu bauen und uml-diagramme zu zeichnen. wenn die objekte einfach tun, was ich von ihnen erwarte, ist das schon ok.
klar war in der frühen zeit von c++ (und die frühe zeit von c++ in diesem sinne wird in manchen unternehmen noch in 10 jahren aktuell sein) ein explorativer wildwuchs an der tagesordnung, der, wenn man die richtige datei angeguckt hat, in 5 minuten zu maximaler verwiirung geführt hat und schwach besaitete gemüter mussten mit dem krankenwagen weggefahren werden. das ist halt der preis einer freien sprache.
-
class Math { public: static double sqrt(double x) { return x*x; } static double sqr (double x, int t) { double y = x; for (int i = 0; i < t; i++) { y *= x; } return y; } ... };
Die Frage ist immer, wie man das Ganze zusammenfasst.
Für sqrt allein ist eine Klasse unsinn. Wenn man nun aber noch andere mathematische Funktionen nutzt, dann ist das schon was anderes..
-
DocJunioR schrieb:
class Math { public: static double sqrt(double x) { return x*x; } static double sqr (double x, int t) { double y = x; for (int i = 0; i < t; i++) { y *= x; } return y; } ... };
Die Frage ist immer, wie man das Ganze zusammenfasst.
Für sqrt allein ist eine Klasse unsinn. Wenn man nun aber noch andere mathematische Funktionen nutzt, dann ist das schon was anderes..bei dir ist die wurzel als das quadrat. aha
-
DocJunioR schrieb:
class Math { public: static double sqrt(double x) { return x*x; }
warum nicht in die klasse double rein?
-
DocJunioR schrieb:
class Math { public: static double sqrt(double x) { return x*x; } static double sqr (double x, int t) { double y = x; for (int i = 0; i < t; i++) { y *= x; } return y; } ... };
Die Frage ist immer, wie man das Ganze zusammenfasst.
Für sqrt allein ist eine Klasse unsinn. Wenn man nun aber noch andere mathematische Funktionen nutzt, dann ist das schon was anderes..Das ist keine Objekt Orientierte Programmierung. Ein Code ist ja nicht OO nur weil es das Wort class missbraucht äh enthält. Für so etwas gibt es in C++ übrigens Namespaces
-
rüdiger schrieb:
DocJunioR schrieb:
class Math { public: static double sqrt(double x) { return x*x; } static double sqr (double x, int t) { double y = x; for (int i = 0; i < t; i++) { y *= x; } return y; } ... };
Die Frage ist immer, wie man das Ganze zusammenfasst.
Für sqrt allein ist eine Klasse unsinn. Wenn man nun aber noch andere mathematische Funktionen nutzt, dann ist das schon was anderes..Das ist keine Objekt Orientierte Programmierung. Ein Code ist ja nicht OO nur weil es das Wort class missbraucht äh enthält. Für so etwas gibt es in C++ übrigens Namespaces
In eine 100% OOP-Sprache machma das aber so.
C++ ist ja keine 100% OOP-Sprache, es vereint ja viele Programmierparadigmen in einer Sprache.