Einzelnen Beitrag anzeigen

Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#17

Re: OOP Problem: änderungen werden nicht übernommen

  Alt 26. Dez 2005, 14:43
Kein Thema, hab auch kein ICQ (und auch nicht vor in nächster Zeit etwas daran zu ändern). In welchem Channel finde ich dich denn?

Zitat:
aber was ich an dieser sache immer noch nicht verstehe ist warum das verwalen erst zum schluss kommt.
Die Details kommen zum Schluß. Die Herangehensweise ist eigentlich denkbar einfach, du gehst immer von unabhängigsten Objekt (oder einem der unabhängigsten Objekte, wenn es mehrere gibt) zum nächsten.
Wenn du sagen wir einen BaseButton, einen Button, einen SpeedButton hast, wobei dies auch die Spezialisierung ist (BaseButton -> Button -> SpeedButton), dann kannst du nicht mit dem SpeedButton anfangen. Du könntest dort zwar alles Eigenschaften des SpeedButton reinschreiben, aber die von einem Button hat ein Speedbutton schließlich auch.
Würdest du mit dem SpeedButton anfangen, könntest du dort alle Eigenschaften reinschreiben, die die auch ein Button hat wieder löschen und den Button entwerfen, hier dann die entfernen, die auch ein BaseButton hat...

Schöner ist mit dem kleinsten gemeinsamen anzufangen. Das kannst du dann in kleinen Schritten erweitern. Wenn dein BaseButton erstmal nur ein Rechteck ist, ist das super. Ein Rechteck lässt sich leicht implementieren. Ist das fertig, kommt vielleicht ein Text in den BaseButton, wieder nur ein kleiner Schritt. Kleine Schritte bedeuten weniger Fehler.
Wenn du erst alle Eigenschaften festlegst und TopDown arbeitest, erschlägt dich das bei einem Speedbutton. Es gäbe soviel zu tun, dass du nicht weißt wo du anfangen solltest (aber du kannst es machen).

Ähnlich ist es mit der Modellierung. Bevor du etwas verwalten kannst, muss etwas zum verwalten existieren. Deshalb fängst du mit etwas ganz einfachem an, was eigentlich nichts braucht (ausser dem Delphi gegegebenen). Basiert etwas auf dieser Klasse, ist das kein Problem, die Klasse hast du dann ja schon fertig.
Wenn du alle Lebewesen der Welt kennst, kannst du leicht eine Welt erschaffen, auf der sie alle Leben können, du weißt ja schon was für Lebewesen existieren. Würdest du sonst eine Welt schaffen, die Wasser hat (weil du Fische planst), dann würdest du in Ruhe die Fische entwerfen, dann die Wale, dann die Ameisen, OH, Moment, Ameisen brauchen Land. Ok, kein Thema du schaffst auch noch Land. Dann schaffst du die Affen, Mensch, jetzt brauchst du auch noch Bananen und Bäume, ...

Verstehst du was ich meine? Du kannst auch mit der Verwaltung anfangen, aber es wäre schwerer im Nachhinein anzupassen. An sich kannst du auch eine Verwaltung planen, aber nicht konkret. Bleib da einfach flexibel. Merk dir nur, dass es eine Art zu speichern gibt, nicht mehr. Du weißt man speichert indem man etwas hinzufügt, etwas entfernt und sich mal anguckt was es schon gibt. Das ist alles. Wie man genau hinzufügt oder entfernt ist doch erst wichtig wenn du wirklich speichern möchtest.

Ich häng dir mal ein sehr einfaches UML-Diagramm an. Weiß nicht ob du mal damit gearbeitet hast, die sind glaube ich nur Teilweise intuitiv. Es soll dir einfach nur die Modelierung erklären. Die Pfeile würden die meisten Menschen immer in umgekehrter Richtung setzen wollen. Zur Erklärung, sie heißen Verallgemeinerung (man könnte sie so auffassen). Du zeigst immer auf eine Verallgemeinerung. Also würde ein Schimpanse auf Affe Zeigen, Affe auf Säugetier, Säugetier auf Tier, ...
Interfaces sind Schnittstellen, die +, - und # Zeichen stehen nur für public, private und protected.

Hoffe es hilft dir überhaupt. Wäre nur eine Möglichkeit es zu modelieren. Wichtig ist, es gibt immer viele Arten der Modellierung, aber es ist nicht nur eine richtig!
Verwende immer (auch beim Diagramm) den Grundsatz für alle Probleme der Informatik : Teile und Herrsche. Schau dir nicht alles auf einmal an, sondern wirklich in kleinen Stücken, dass macht es leichter.

Ich versuch dir mal hier das Diagramm zu erklären. Es ist wie gesagt nicht vollständig.
Fang am Besten oben Links an, da hast du das Interface Drawable (Zeichenbar). Es hat eine Funktion Draw, dass war's auch schon. Nun nimm den Pfeil mit der gestrichelten Linie, der auf dieses Interface zeigt und folge ihm. Er kommt von TVisibleBaseClass. Die Klasse ist in zwei Teile geteilt. In der oberen Hälfte stehen die Variablen, das Minuszeichen heißt dass sie alle private sind.
In der unteren Hälfte stehen die Funktionen. Ein plus heißt sie sind public, eine # protected. Was für Felder es hier gibt und was für Methoden ist eigentlich erstmal egal, sollte nur grob was zeigen. Wichtiger ist der Pfeil. Du zeigst auf eine Generalisierung oder anders gesagt, TVisibleBaseClass ist ein spezielles IDrawable (es kann alles was IDrawable kann und mehr). Hier heißt dass, das jede TVisibleBaseClass immer ein Draw beherrscht.
Das macht natürlich nur Sinn, wenn auch jedes Sichtbare Element von dieser Klasse erbt (dafür musst du dann halt sorgen).

Schau dir nun die anderen beiden Schnittstellen an (ohne die Pfeile). Es sind die zwei weiteren obersten Kästchen, IContainer und IContainable. Fangen wir mit letzterer an. IConainable ist leer. Das ist auch beabsichtigt.
IContainable sollen einfach alle Elemente werden, die abgelegt werden können. Warum dieses Interface? Ganz einfach, auch deine GUI wird viele Eigenschaften der Sichtbaren Elemente haben. Sie muss auch gezeichnet werden, hat auch Position und Breite sowie Höhe, ...
Aber auf ein Panel wirst du sicherlich keine Form legen wollen, oder? Ich würde es jetzt so wie in Delphi machen und nein sagen. Deshalb muss es eine Eigenschaft geben, die eine GUI eben nicht hat. Dies ist durch das Interface gegeben. Folge dem gestrichelten Pfeil von IContainable zur TContainableBaseClass. Es heißt, dass jede TContainableBaseClass auch Containable ist. Von dieser Klasse (die keine eigenen Methoden braucht) geht ein Pfeil nach oben zur TVisibleBaseClass. Dieser durchgezogene Pfeil heißt, TContainableBaseClass erbt von TVisibleBaseClass. Alles was also in TVisibleBaseClass steht, hat TContainableBaseClass auch.
Beachte nur kurz, dass das Kästchen TGui keinen Pfeil zu TContainableBaseClass hat und keinen zum Interface Containable. Damit fehlt TGUI also diese Eigenschaft.

Ok, zurück nach oben zum Interface in der Mitte. IContainer ist das Interface, dass alle Objekte implementieren sollen, wenn sie andere aufnehmen/verwalten können. Was braucht man um verwalten zu können? Na ja, eine Möglichkeit etwas hinzu zu fügen, etwas zu entfernen und natürlich die Möglichkeit aufs Gespeicherte zu zu greifen. Es muss nicht so aussehen wie hier! Die Möglichkeiten könnte man (sollte man) deutlich flexibler wählen.

Zwischen IContainer und IContainable gibt es eine Linie mit einem Karo dran. Da steht auch noch ein 1 * dran. Ist das Karo wie hier innen weiß, so nennt man das eine Aggregation. Das bedeutet soviel wie : IContainer besteht unter anderem aus Elementen vom Typ IContainable. Ist hier eigentlich falsch, da nur Klassen Elemente aufnehmen können, wollte aber nicht noch extra eine Klasse zwischen setzen.
Die 1 * heißt, dass 1 IContainer beliebig viele (auch 0) IContainable aufnehmen kann.

Das wäre die oberste Zeile, die drei Interfaces. Schau dir nun die beiden gestrichelten Linien die von IContainer weggehen an. Sie gehen zu TGui und TVisiblePanel. Anders gesagt, alle Objekte die später andere Aufnehmen können müssen das Interface IContainer implementieren (es gilt auch umgekehrt, alles was IContainer implementiert kann später Objekte aufnehmen). Es ist auch schon festgelegt was für Objekte, es müssen welche vom Typ IContainable sein.

Nun bleiben eigentlich nur noch die Pfeile die von TContainableBaseClass weggehen übrig. Diese kommen von TVisibleButton und TVisiblePanel. Wie du siehst, sind diese Elemente damit vom Typ IContainable (erben sie von TContainableBaseClass) und vom Typ TVisibleBaseClass (auf gleiche Weise geerbt), TGui erbt nur von TVisibleBaseClass.
Ein TVisiblePanel kann zu dem als Container dienen, die TGui auch, ein TVisibleButton hingegen nicht. Ihm fehlt eine Beziehung zu IContainer.

Ich weiß nicht, ob das jetzt wirklich anschaulicher ist oder nicht, aber das ist der Gedanke den du vervollständingen müsstest. Es ist noch überhaupt nicht festgelegt, ob ein Button später ein Rechteck, ein Dreieck oder ein Kreis ist. Aber es ist im Moment noch nicht wichtig. Auch die Verwaltung ist hier schon geplant, aber eben noch nicht konkret. So modellierst du erstmal so weit wie es dir möglich ist (es sollte halt ein einfaches Modell bleiben). Man kann sich natürlich auch tot modellieren, aber du hattest ja eine Vorstellung, was du für den Anfang haben möchtest, wie gesagt Erweitern ist sicher nicht das Problem.
Wenn du dass erstmal modelliert hast, dann geht es erst an die Implementierung und auch dort jede Klasse für sich. Wenn du dann etwas implementierst, brauchst du nur dein Modell umzusetzen, das überlegen über mögliche Abhängigkeiten und sowas wie, wie kann die Gui Elemente aufnehmen, die erst noch geschrieben werden entfällt. Würdest du jetzt ein TVisibleMemo schreiben, musst du nur gucken wovon es erbt und es könnte ohne Änderung der Gui von dieser oder einem Panel verwaltet werden (wenn es ein IContainer ist).
Damit kannst du die Implementierung sehr viel einfacher durchführen.

Die ist dann aber eine andere Sache. Dort fängst du dann übribens immer mit den Klassen / Interface an, auf die nur gezeigt wird. Die anderen besitzen eine Abhänigkeit von diesen Klassen/Interfaces (kann nur von Dingen die es gibt erben).

Gruß Der Unwissende
Angehängte Dateien
Dateityp: pdf visio-zeichnung1__1__162.pdf (44,8 KB, 8x aufgerufen)
  Mit Zitat antworten Zitat