Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
Wenn ich das richtig sehe, zeigst Du hier nur die Mechanik, um letztendlich an gw_setup::callback_pt zu delegieren.
Das ist eigentlich nur die Benachrichtigung an das Hauptprogramm.
| setup_box = new gw_setup( ... );
setup_box->callback( notify_cb );
|
| void gw_setup::callback( Fl_Callback * cb ) {
callback_pt = cb;
}
|
Ich versuche immer erst auf einer abstrakteren Ebene zu verstehen, was das Ziel ist bzw. welche Aufgabe erledigt wird.
Genau damit habe ich oft meine Probleme. Ich benötige immer etwas zum anfassen, und wenn es nur Papier und Bleistift sind.
Ich würde ein Interface für ein Proxy-Objekt und dann mehrere implementierende Klassen definieren, die alle relevanten Daten enthalten, mit denen es die nötige Arbeit im Callback-Fall erledigen kann.
Das sieht interessant aus. Das muss ich mal näher untersuchen. Das kann jetzt aber etwas dauern, da ein Teil meiner Aufmerksamkeit momentan von der Snooker WM beansprucht wird (bis Anfang Mai mehrere Sendungen täglich auf Eurosport).
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
Dakuan schrieb: Wenn ich das richtig sehe, zeigst Du hier nur die Mechanik, um letztendlich an gw_setup::callback_pt zu delegieren.
Das ist eigentlich nur die Benachrichtigung an das Hauptprogramm.
Das widerspricht sich ja nicht. ☺
| setup_box = new gw_setup( ... );
setup_box->callback( notify_cb );
|
| void gw_setup::callback( Fl_Callback * cb ) {
callback_pt = cb;
}
|
Ja, hier wird die Bühne bereitet (also der Callback gespeichert), damit dann in gw_setup::do_callback die Show aufgeführt werden kann.
Ich versuche immer erst auf einer abstrakteren Ebene zu verstehen, was das Ziel ist bzw. welche Aufgabe erledigt wird.
Genau damit habe ich oft meine Probleme. Ich benötige immer etwas zum anfassen, und wenn es nur Papier und Bleistift sind.
Ich versuche, so etwas immer top-down anzugehen, weil man dabei das Ziel besser im Auge behalten kann. Man kann das auch mit Papier und Bleistift auf CRC-Karten machen. Ich beobachte das allerdings öfters, dass viele in der Softwareentwicklung gerne mit Details arbeiten, weil die konkret und fassbar sind, aber die abstrakteren Ebenen nicht so gerne haben. Ich halte das tatsächlich für ein Problem in der Softwareentwicklung. Vielleicht hilft es Dir, Dich ein wenig mit Abstrakten Datentypen zu beschäftigen. Das spannende ist hier, dass man sich eigentlich nur mit der Semantik der öffentlichen API auseinandersetzt und die Implementierungsdetails völlig ignoriert. Das kommt den Aspekten von Encapsulation und Information Hiding in der OO sehr entgegen. Ich muss allerdings auch sagen, dass es mich anfangs eine ganze Weile gekostet hat, bis ich die Idee von OOP verstanden habe.
Das sieht interessant aus. Das muss ich mal näher untersuchen. Das kann jetzt aber etwas dauern, da ein Teil meiner Aufmerksamkeit momentan von der Snooker WM beansprucht wird (bis Anfang Mai mehrere Sendungen täglich auf Eurosport).
Viel Spaß - bei beidem! 😉
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
Viel Spaß - bei beidem!
Danke. Ist gerade Pause - daher antworte ich schon mal bevor ich wieder etwas vergesse.
Ich versuche, so etwas immer top-down anzugehen, weil man dabei das Ziel besser im Auge behalten kann.
Das kenne ich auch, seit ich damals "Algorithmen und Datenstrukturen" von N. Wirth gelesen hatte.
Aber ich denke, das kann man nur machen, wenn man weiß, das man alle Bausteine zusammen hat, Ich beobachte das allerdings öfters, dass viele in der Softwareentwicklung gerne mit Details arbeiten, weil die konkret und fassbar sind, aber die abstrakteren Ebenen nicht so gerne haben.
Das hatte ich auch schon einige Male, aber aus einem anderen Grund.
Wenn es mir nicht gelingt das Kernproblem irgendwie in den Griff zu bekommen, brauche ich mir über den Rest des Programms keine Gedanken zu machen.
Es nützt nichts ein gut designtes Programm zu haben, dem die eigentliche Funktionalität fehlt.
So etwas kann natürlich nur passieren, wenn man neue Themenbereiche betritt, was bei mir allerdings öfters zutrifft. Beispiel: als ich anfing mich mit digitaler Signalverarbeitung zu befassen, hatte ich keine Ahnung, was da alles auf mich zukommt, auch wenn ich nur an der Oberfläche kratzen will... Da hatte ich erstmal Null Vorstellung wie das aufzuteilen ist und bin gefühlt 17.000 Mal auf die Nase gefallen.
Ich muss allerdings auch sagen, dass es mich anfangs eine ganze Weile gekostet hat, bis ich die Idee von OOP verstanden habe.
Ja, dieser Lernprozess ist bei mir wohl noch lange nicht abgeschlossen. Ich erkenne Sackgassen ja erst, wenn es nicht mehr weiter geht.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
Dakuan schrieb:
Ich versuche, so etwas immer top-down anzugehen, weil man dabei das Ziel besser im Auge behalten kann.
Das kenne ich auch, seit ich damals "Algorithmen und Datenstrukturen" von N. Wirth gelesen hatte.
Aber ich denke, das kann man nur machen, wenn man weiß, das man alle Bausteine zusammen hat,
Das sehe ich anders. Der Punkt ist ja, dass man erst mal die groben Linien zieht und sich nicht um Details kümmert. Das verfeinert man dann nach "unten" zu mehr und mehr Detaillierung.
Ich beobachte das allerdings öfters, dass viele in der Softwareentwicklung gerne mit Details arbeiten, weil die konkret und fassbar sind, aber die abstrakteren Ebenen nicht so gerne haben.
Das hatte ich auch schon einige Male, aber aus einem anderen Grund.
Wenn es mir nicht gelingt das Kernproblem irgendwie in den Griff zu bekommen, brauche ich mir über den Rest des Programms keine Gedanken zu machen.
Es nützt nichts ein gut designtes Programm zu haben, dem die eigentliche Funktionalität fehlt.
Ich sehe da keinen Widerspruch: wenn man in mehr Detaillierung eintaucht, hat man ja die freie Wahl, an welcher Stelle man damit beginnt. Es macht ja durchaus Sinn, erst in den wichtigen Kernbereich zu gehen und erst danach Parsen der Kommandozeile und was auch immer anzugehen. Trotzdem ist es m.E. sehr sinnvoll, sich erst einmal über die funktionalen Bereiche klar zu werden, die das Programm am Ende haben muss, und zu klären, welche miteinander interagieren müssen. Sonst hast Du die Kernfunktionalität erschlagen und stellst am Ende fest, dass sie aber nicht mit einer anderen wichtigen Funktionalität interagiert, weil Du daran nie gedacht hast. Du kannst ja sogar den Kernteil schon implementieren und nutzt erst mal Dummies oder eine API zur Kommunikation mit den anderen Bereichen, die erst mal nix tun.
So etwas kann natürlich nur passieren, wenn man neue Themenbereiche betritt, was bei mir allerdings öfters zutrifft.
Es gibt die Ansicht, dass wir mit praktisch jedem Projekt Neuland betreten. Und die ist auch nicht so falsch. Deswegen hat ja Fred Brooks auch gesagt "Plan to throw one away." Man soll also am ersten Wurf lernen und mit dem gewonnenen Wissen noch einmal neu anfangen. Hängt natürlich immer vom Projekt ab: es gibt Lösungen, die man mit einer gewissen Erfahrung in ähnlichen Bereichen bereits im ersten Wurf gut hinbekommt.
Beispiel: als ich anfing mich mit digitaler Signalverarbeitung zu befassen, hatte ich keine Ahnung, was da alles auf mich zukommt, auch wenn ich nur an der Oberfläche kratzen will... Da hatte ich erstmal Null Vorstellung wie das aufzuteilen ist und bin gefühlt 17.000 Mal auf die Nase gefallen.
Deswegen kannst Du aber trotzdem am Anfang festlegen, dass Du eine Schnittstelle für die Annahme der Daten brauchst und eine Senke für das Abliefern der verarbeiteten Signaldaten. Du kannst festlegen, wie viel Durchsatz diese Schnittstellen liefern müssen etc. Du kannst auch identifizieren, dass Du Logging brauchst und wofür, dass Du irgendwie konfigurieren musst usw. Gerade bei der Verarbeitung von Massendaten ist es sinnvoll sich zu überlegen, wo man z.B. aggregieren kann, um das Volumen zu reduzieren, oder zu klären, wie die Daten durchs System fließen sollen, damit es möglichst effizient ist.
Ich muss allerdings auch sagen, dass es mich anfangs eine ganze Weile gekostet hat, bis ich die Idee von OOP verstanden habe.
Ja, dieser Lernprozess ist bei mir wohl noch lange nicht abgeschlossen. Ich erkenne Sackgassen ja erst, wenn es nicht mehr weiter geht.
Das ist doch gut! Es gibt Leute, die merken es nicht mal dann. ☺
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
Da war ich wohl wieder zu ungenau. Mit "Kernproblem lösen" oder "alle Bausteine zusammen haben" meinte ich, dass ich mir sicher bin oder zumindest eine genaue Vorstellung davon habe, das und wie ich das Problem lösen kann. Aktuell habe ich so ein Problem, wo ich damit seit Wochen nicht weiter komme, obwohl mir der Quelltext von 2 Programmen vorliegt, die genau mein Problem lösen. Das Projekt liegt daher erstmal auf Eis.
Man soll also am ersten Wurf lernen und mit dem gewonnenen Wissen noch einmal neu anfangen.
Das habe ich auch schon unfreiwillig erfahren. Bei einem meiner Projekte hat erst der dritte Neuanfang zu einem brauchbaren Ergebnis geführt, was mehrere Jahre gedauert hat. Ich war dann so erleichtert, das ich die Zahl 3 im Programmnamen eingebaut habe ☺ Übrigens: mit den Begriffen "Proxy" und "Adapter" hast Du mir einiges an Hausaufgaben mitgegeben. Mir war anfangs nicht klar, das es sich dabei um Mitglieder der Viererbande handelt.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
Dakuan schrieb: Da war ich wohl wieder zu ungenau. Mit "Kernproblem lösen" oder "alle Bausteine zusammen haben" meinte ich, dass ich mir sicher bin oder zumindest eine genaue Vorstellung davon habe, das und wie ich das Problem lösen kann.
Ich bin mir nicht sicher, dass ich Dich richtig verstehe. Meinst Du damit, dass Du erst wissen willst, wie sich die Kernbereiche des Programms verhalten sollen, bevor Du das ganze auf einer höheren Abstraktionsebene betrachtest? Da würde ich dann tatsächlich sagen, das ist nicht die Reihenfolge, die ich mit "top down" meine. ☺
Übrigens: mit den Begriffen "Proxy" und "Adapter" hast Du mir einiges an Hausaufgaben mitgegeben. Mir war anfangs nicht klar, das es sich dabei um Mitglieder der Viererbande handelt.
☺ Ich bin da allerdings immer etwas zwiegespalten: einerseits ist es gut, die ganzen Entwurfsmuster zu kennen, weil die (hoffentlich alle) Möglichkeiten der Zusammenarbeit zwischen Klassen und Objekten beschreiben. Auf der anderen Seite suggeriert die Anzahl der Muster, dass sie alle klar voneinander abzugrenzen sind. Aber die Unterschiede zwischen manchen Mustern sind so minimal, dass die Abgrenzung mitunter schwer fällt. Man kann dann schon wieder anfangen ein paar wenige Meta-Muster zu erkennen, z.B. bei allen Mustern, bei denen ein Objekt an ein anderes delegiert und dieses andere wird von Zeit zu Zeit ausgewechselt (Strategy z.B.). Dann ist der Unterschied nur noch, unter welchen Bedingungen die Referenz ausgewechselt wird, aber der abstrakte gleiche Kern ist, dass man überhaupt delegiert und der Empfänger wechselt.
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
Ich bin mir nicht sicher, dass ich Dich richtig verstehe.
Ok, dann mal ein konkretes Beispiel: Ich möchte einen Morsedecoder programmieren. Eigentlich kein unlösbares Problem. Hatte ich vor Jahren schon einmal unter DOS auf einem 286-er probiert. Da allerdings nur mit den Impulsen von der seriellen Schnittstelle. Unter DOS konnte man ja noch ungestraft auf Hardware zugreifen und eigene Interrupt Service Routinen installieren. Aber unter Windows und Linux geht das nicht mehr. Sackgasse. Wenn man jetzt so etwas machen möchte, ist der normale Weg über die Audio Schnittstelle zu gehen und sich die gewünschte Tonfrequenz aus dem Frequenzgemisch heraus zu angeln. Ich habe fast 2 Jahre gebraucht um herauszufinden wie man das macht. Das war dann der Baustein, mit dem das neue Projekt erst möglich wurde. Vorher machte es keinen Sinn sich über ein Design Konzept Gedanken zu machen.
Aber die Unterschiede zwischen manchen Mustern sind so minimal, dass die Abgrenzung mitunter schwer fällt.
Und ich dachte schon, ich bin schon zu verkalkt, um das zu erkennen und hatte daher das Buch wieder weg gelegt.
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
Dakuan schrieb: Ok, dann mal ein konkretes Beispiel: Ich möchte einen Morsedecoder programmieren. Eigentlich kein unlösbares Problem. Hatte ich vor Jahren schon einmal unter DOS auf einem 286-er probiert. Da allerdings nur mit den Impulsen von der seriellen Schnittstelle. Unter DOS konnte man ja noch ungestraft auf Hardware zugreifen und eigene Interrupt Service Routinen installieren. Aber unter Windows und Linux geht das nicht mehr. Sackgasse.
Muss man sowas unbedingt mit einem dicken PC lösen? Da bietet sich ein µC doch gerade zu an: http://z12.vfdb.org/der-ov-z12/fieldday-2016/arduino-morsedecoder/ - und die dekodierten Zeichen kann man dann immer noch über eine serielle Schnittstelle an den PC bringen ☺
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
Dakuan schrieb:
Aber die Unterschiede zwischen manchen Mustern sind so minimal, dass die Abgrenzung mitunter schwer fällt.
Und ich dachte schon, ich bin schon zu verkalkt, um das zu erkennen
Bestimmt nicht!
und hatte daher das Buch wieder weg gelegt.
Ist ja auch eher ein Lexikon. Das liest sich auch nicht so toll.
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
Muss man sowas unbedingt mit einem dicken PC lösen?
Nein, muss man nicht, wenn man bereit ist mit einigen Unzulänglichkeiten des Goetzel Algorithmus' zu leben und wenn man auch auf Abstimmhilfen wie Spektrumsanzeige verzichten kann. Ist aber interessant. Ich frage mich allerdings, wie die krumme Abtastfrequenz von 8928 Hz zustande kommt.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
Eine Sache ging mir noch durch den Kopf, als ich über dieses Thema nachdachte: eigentlich macht die OOP ja nur explizit, was man implizit auch Prozedural macht. Es gibt Datenstrukturen (die Zustand repräsentieren) und Funktionen, die diese manipulieren (Zustand auslesen und verändern). Die OOP macht das explizit und koppelt diese Funktionen direkt an die Strukturen. Insofern kann man Entwurfsmuster nicht nur in OO-Programmen sondern in allen Programmen entdecken - und natürlich anwenden.
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
Eigentlich hatte ich schon immer versucht, meine Funktionseinheiten voneinander abzugrenzen. Allerdings ist mir das nicht immer wirklich gelungen (manchmal war ich einfach zu bequem). Wirklich über OOP denke ich erst nach, seit ich mich mit FLTK und C++ beschäftige. Insofern kann man Entwurfsmuster nicht nur in OO-Programmen sondern in allen Programmen entdecken - und natürlich anwenden.
Entwurfsmuster sind eine Hürde, an der ich noch arbeiten muss. Auch wie man daraus ein Konzept für eine GUI baut. Bei einfachen CLI Programmen ist das ja einfach, wenn man da nur die Parameter abfragen muss. Ich denke zwar, dass ich das OOP Konzept verstanden habe, aber bei der Umsetzung passieren mir immer wieder Fehler. Ich entdecke in alten Programmen immer wieder Fälle, wo die Aufteilung der zu erledigenden Aufgaben auf die Klassen irgendwie unzweckmäßig geraten sind. Ich tendiere irgendwie dazu zu viel in einer Klasse zusammenfassen zu wollen (vermute ich). Dein Beispiel hat mir übrigens gezeigt, dass ich mich noch einmal mit einigen C++ Grundlagen befassen muss. Ich hatte virtuelle Methoden einfach übersprungen, weil ich dachte so etwas kommt bei mir nicht vor. Tatsächlich hatte ich diese aber schon mehrfach verwendet, aber nie selber so deklariert. Das ist mir gestern erst durch eine neue Fehlermeldung aufgefallen. Zu meinem ursprünglichen Problem: Ich habe daran zwar noch nicht wirklich weiter gearbeitet, aber ich tendiere momentan dazu nur Strings auszutauschen, da es ja eigentlich auch nur um Strings geht. Da werden URLs verarbeitet und nach vorgegebenen Mustern Dateinamen generiert. Da muss das Panel dann eben eine Konvertierung vornehmen (ich habe jetzt bewusst den Begriff adaptieren vermieden). P.S. ab 20:00 bich ich nicht mehr ansprechbar 😉 Ding Junhui vs Ronnie O’Sullivan hat etwas von einem vorweg genommenen Finale. Das kann 'ne lange Nacht werden.
|
ChickenLipsRfun2eat
Anmeldungsdatum: 6. Dezember 2009
Beiträge: 12067
|
Dakuan schrieb: ...Ich tendiere irgendwie dazu zu viel in einer Klasse zusammenfassen zu wollen (vermute ich).
Ich auch. Da hilft es mir manchmal mir das aufzumalen. Ab und an ist es aber auch einfach "quick and dirty" eine Funktion in eine Klasse zu packen, die an sich nur an einer Stelle gebraucht wird, weil sie eben an den Daten dran ist. Ich weiß da auch nie, wo ich die Grenze setzen soll. Geht also auch "Neulingen" wie mir so.
P.S. ab 20:00 bich ich nicht mehr ansprechbar 😉 Ding Junhui vs Ronnie O’Sullivan hat etwas von einem vorweg genommenen Finale. Das kann 'ne lange Nacht werden.
Würde ich auch gerne gucken...
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
ChickenLipsRfun2eat schrieb: Dakuan schrieb: ...Ich tendiere irgendwie dazu zu viel in einer Klasse zusammenfassen zu wollen (vermute ich).
Ich auch.
Ich glaube, das ist recht weit verbreitet, weil eine Klasse of als etwas gesehen wird, das "schwer" ist (im Vergleich zu einer "leichten" Funktion z.B.). Das hängt vielleicht auch davon ab, welche Sprache und Entwicklungsumgebung man verwendet. Ich glaube allerdings, dass man der Tendenz zuwenige Klassen zu erzeugen entgegen wirken sollte, weil man ansonsten schlechtere Modularisierung erreicht.
Da hilft es mir manchmal mir das aufzumalen. Ab und an ist es aber auch einfach "quick and dirty" eine Funktion in eine Klasse zu packen, die an sich nur an einer Stelle gebraucht wird, weil sie eben an den Daten dran ist. Ich weiß da auch nie, wo ich die Grenze setzen soll. Geht also auch "Neulingen" wie mir so.
Ich glaube, es spricht nichts dagegen, solche Funktionen in eine Klasse zu packen - insbesondere, wenn sie privat sind. Wenn sich das dann auswächst, sollte man überlegen, ob man das nicht auslagert. Refactoring ist halt immer wichtig.
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
Ich glaube allerdings, dass man der Tendenz zuwenige Klassen zu erzeugen entgegen wirken sollte, weil man ansonsten schlechtere Modularisierung erreicht.
Da habe ich bei FLTK einige Beispiele gefunden, wie man so etwas machen kann. Da gibt es dann Klassennamen mit Unterstrich:
Class_Name_
Damit wird dann nur die gemeinsame Grundfuktionalität für eine Gruppe ähnlicher Klassen, die davon abgeleitet sind, bereit gestellt. Anfangs fand ich das nur ärgerlich, weil ich ständig einzelne Methoden gesucht hatte.
Ab und an ist es aber auch einfach "quick and dirty" eine Funktion in eine Klasse zu packen, die an sich nur an einer Stelle gebraucht wird, weil sie eben an den Daten dran ist.
Das kenne ich auch, sehe das aber nicht ganz so schlimm. Jedenfalls wenn es thematisch und logisch passt. Ich hatte da kürzlich so eine Funktion, die auch noch nicht einmal direkt auf Daten der Klasse zugreift (nur über Pointer). Die habe ich dann kurzerhand als statisch deklariert, damit sie auch ohne Bezug zu einer Instanz verwendbar ist.
Refactoring ist halt immer wichtig.
Aber nicht immer leicht. Meine Konstruktoren für div. digitale Filter fangen langsam an zu wuchern und wachsen mir über den Kopf. Bei einigen gibt es Gemeinsamkeiten, aber andere sind sehr speziell. Dazu kommt dann noch, das eine neue Aufteilung auch irgendwie mit dem Einstell-Menü abgestimmt werden muss. Da fehlt mir noch ein neues Konzept.
Würde ich auch gerne gucken...
O’Sullivan ist leider raus (13:10) 😢
|