OOP: soll man jetzt alles in ne Klasse packen oder watt?
-
DEvent schrieb:
Klar macht man aus allem eine Klasse.
Nenn mir mal ein Beispiel wo es sich absolut nicht auszahlt es in eine Klasse zu packen.double sqr(double x){ return x*x; }
wenn man das is eine klasse packen sollte, dann in double rein. das geht aber nacht. dann lieber ohne klasse.
-
DEvent schrieb:
Ist halt OOP. Wems nicht gefällt, kann ja LISP oder PROLOG nehmen :p
http://de.wikipedia.org/wiki/Common_Lisp_Object_System
Seit 1994 ANSI-standardisiert.
-
DEvent schrieb:
Ist halt OOP. Wems nicht gefällt, kann ja LISP oder PROLOG nehmen :p
Klassen wie MenuDatei, MenuBearbeiten und MenuHilfe sind alles andere als OOP. Das sind so richtig typische "alles-was-ich-angreifen-kann-ist-eine-Klasse"-Designs, wenn man es denn als Design bezeichnen darf.
Typischerweise lassen sich halt Algorithmen eher schlecht in einem objektorientierten System abbilden, aber statische Methoden gibts ja auch nicht umsonst.
-
volkard schrieb:
DEvent schrieb:
Klar macht man aus allem eine Klasse.
Nenn mir mal ein Beispiel wo es sich absolut nicht auszahlt es in eine Klasse zu packen.double sqr(double x){ return x*x; }
wenn man das is eine klasse packen sollte, dann in double rein. das geht aber nacht. dann lieber ohne klasse.
Aha und das ganze im globalen namespace ? Was ist wenn ich meine eigene Implementation der sqr-Funktion haben will.
-
Klassen wie MenuDatei, MenuBearbeiten und MenuHilfe sind alles andere als OOP. Das sind so richtig typische "alles-was-ich-angreifen-kann-ist-eine-Klasse"-Designs, wenn man es denn als Design bezeichnen darf.
Was spricht den dagegen ?
In den Ctors siehts dann so aus:Hauptfenter() { hauptframe.setMenu(new Menüs()); } Menüs() { add(new MenuDatei()); add(new MenuBearbeiten()); add(new MenuHilfe()); }
Man hat schnell die Übersicht, man braucht nicht die Implementation der Menüs sehen, wenn man nicht will. Wenn man doch sehen will wie das Menu Datei aufgebaut ist, geht man flott in die Klasse MenuDatei rein.
Also ich sehe nur Vorteile.
-
DEvent schrieb:
Was ist wenn ich meine eigene Implementation der sqr-Funktion haben will.
Dann überdeck ich die globale Version einfach in einem lokaleren Scope. Aber Funktionen ansich als Hilfsmittel für allgemeine Aufgaben sind ja kein Argument gegen Klassen, wie man z.B: auch mit static imports in Java sehen kann (auch wenn ich es deswegen nicht zwangsweise gutheiße).
-
Man hat schnell die Übersicht, man braucht nicht die Implementation der Menüs sehen, wenn man nicht will. Wenn man doch sehen will wie das Menu Datei aufgebaut ist, geht man flott in die Klasse MenuDatei rein.
Also ich sehe nur Vorteile.
Wie wäre es z.B: mit hochgradiger Redundanz als Nachteil? ..
Überleg einfach mal durch was sich die 3 Klassen unterscheiden:
- Text, bzw. Beschreibung
- Listener, der die gewählte Aktion ausführt
- eventuell Icon
Langsam sollte es halt klingeln und offensichtlich werden, dass deine 3 Klassen in Wahrheit 3 Objekte sein sollten.
-
ich erinnere mich auch mit schrecken an
class BubbleSort:public SortAlgorithm...
-
BTW: Wie macht man eigentlich folgendes, wenn man nicht OOP betreiben möchte...
Man hat einen Algorithmus, der sehr lange braucht, deshalb will man den Fortschritt durch eine Art ProgressBar visualisieren.
Im OOP-Fall würde ich mir da praktisch so ne Klasse basteln, wie volkard sie gerade mit dem Sortieren vorgeschlagen hat. Die Objekte dieser Klasse hätten dann halt einen inneren Zustand, der den aktuellen Fortschritt repräsentiert, den man von außen abfragen könnte. Wie macht man das ohne OOP? Da müsste man wohl mit Funktionen arbeiten, die Nebenwirkungen haben - wie auch die entsprechende Methode im OOP-Fall. Diese Nebenwirkungen wären aber nicht gerade lokal oder so... Wie baut man soetwas also vernünftig auf?
-
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.
-
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.
-
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.