Einzelnen Beitrag anzeigen

Der_Unwissende

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

Re: OOP Problem: änderungen werden nicht übernommen

  Alt 25. Dez 2005, 18:26
Zitat von mimi:
was meisnt du mit "setter" ?
Wenn du Properties verwendest, dann ja eigentlich nur aus der Idee heraus, nicht direkt auf einen Wert zu zugreifen. Dafür gibt es gleich mehrere Gründe, einerseits interessierst du dich in der OOP nie für die konkrete Art wie ein Wert abgespeichert wird. Ob es in einer Liste, einem Array, einer Hashtable, einem Baum, einer Halde,.... ist ändert für dich (von aussen kommend) nichts. Das andere ist natürlich, dass du gerne Invarianten überprüfen möchtest (Vor- und Nachbedingungen).
Deswegen sind Variablen in der OOP eigentlich immer privat und du greifst eigentlich nie direkt auf sie zu (es lässt sich immer vermeiden). Statt dessen benutzt du eine Methode, die einen Wert setzt (Setter) und eine Methode die dir einen Wert liefert (Getter).
Natürlich wird dir der Setter häufiger begegnen (hier prüfst du beim setzen ob der Wert gültig ist). Aber auch getter machen Sinn, wenn du zum Beispiel eine Liste von Zahlen hast und die größte Zahl bekommen möchtest, könntest du entweder immer die größte Zahl in einer Variablen speichern oder du sortierst die aufsteigend und nimmst das letzte Element oder du durchläufst die gesamte Liste und suchst das Größte. Wie du siehst leisten alle Methoden genau das gleiche, doch warum sollte es dich von aussen kommend interessieren? Du willst nur das größte Element. Hast du jetzt eine Methode getGreatestOne, liefert die dir irgendwie das Größte Element (alles was du willst).
In Delphi verbergen Properties nur den expliziten Aufruf solcher Methoden (du kannst natürlich auch direkt die Variable schreiben oder lesen).

Zitat von mimi:
Zitat:
Für Draw wäre dann noch interessant wohin du zeichnen lassen möchtest.
dafür ist ja fx und fy veranwortlich oder was meinst du mit dieser frage ?
ich möchte auch nur das obj neu zeichen lassen was sich gerade ändert.
Ich meine du möchtest so etwas wie einen Button zeichnen, dann musst du doch angeben wohin gezeichnet werden soll. Wenn du dir in Delphi die "Draws" anschaust, wirst du häufig sehen, dass man ein Canvas übergibt auf das gezeichnet werden kann. Das wäre eventuell auch bei dir nötig. Aber ich glaube du möchtest jetzt erstmal nur fertige Buttons (u.Ä.) platzieren, oder?

Zitat von mimi:
habe ich. Aber ich weiß im moment nicht was ein Interfaces hier zu tuen hätte ich stelle mir ein interfaces immer so vor:
du möchte eine grafik engine schreiben und möchtes verschiende grafik system verwenden z.b. openGL, DX, Canvas, etc. aber bei meiner GUI wüste ich jetzt nicht wo es da verwendung finden sollte.
Nun ja, Interfaces sind echt wichtig zu verstehen. Sie bieten einem wie gesagt eine Menge Möglichkeiten.
Ein Interface ist erstmal nur eine Sammlung an Methoden. Du weißt nur durch die Dokumentation was die einzelnen Methoden machen sollen und du weißt was für Argumente sie bekommen. Das wars. Ein Interface implementiert aber keine dieser Methoden.
Jede Klasse kann von genau einer Klasse erben, sie kann aber zusätzlich noch beliebig viele Interfaces implementieren. Ein Interface zu implementieren heißt dabei, dass jede abstrakte Methode des Interfaces in der Klasse implementiert werden muss.
Implementiert also eine Klasse ein Interface, so wird dir zugesichert, dass diese Klasse alle Methoden des Interface besitzt.

Das eigentlich Wichtige an diesen Dingern ist eben diese Zusicherung. Wenn du dein Programm erweiterst, möchtest du nicht für jede Erweiterung das Rad neu erfinden (nicht in der OOP). Also versuchst du den gemeinsamen Nenner zu finden und zu verwenden. Wichtig ist, dass jede Klasse immer die Eigenschaften ihrer Vorfahren und der implementierten Interfaces hat. Ein Interface entspricht weitgehend einer abstrakten Klasse, allerdings besitzt ein Interface ausschließlich abstrakte Methoden (eine abstrakte Klasse besitzt nur mindestens eine abstrakte Methode).

Das ganze mal etwas deutlicher an einem Beispiel:

Delphi-Quellcode:
type
  TDrawable = Interface
    procedure setPosX(const Position : Integer);
    procedure setPosY(const Position : Integer);
    procedure Draw(const Canvas : TCanvas);
  end;

  TDrawableButton = class(TInterfacedObject, TDrawable)
    protected
      procedure OnClick;
    public
      procedure setPosX(const Position : Integer);
      procedure setPosY(const Position : Integer);
      procedure Draw(const Canvas : TCanvas);
  end;

  TDrawablePanel = class(TInterfacedObject, TDrawable)
    private
      FPosX, FPosY : Integer;
      FColor : TColor;
    protected
      procedure setColor(const Color : TColor);
    public
      procedure setPosX(const Position : Integer);
      procedure setPosY(const Position : Integer);
      procedure Draw(const Canvas : TCanvas);
      property Color : TColor read FColor write setColor;
  end;
....
  procedure doFoo;
  var Drawable : TDrawable;
  begin
    DrawAble := TDrawablePanel.Create;
    // Achtung, DrawAble hat nur die Eigenschaften des Inteface!
    // also nur die Methoden setPosX/Y und Draw
    DrawAble.Draw(Form1.Canvas);
    ...
  end;
Ok, kein großartiges Beispiel, aber soll ja auch nur kurz etwas zeigen. Hier siehst du erstmal dass du zwei verschieden Objekte mit unterschiedlichen Eigenschaften hast. Ein TDrawableButton hat eine Methode OnClick, aber eben keine Farbe, diese hat dann aber ein TDrawablePanel. Trotzdem sind beide vom Typ TDrawable, besitzen also beide eine Methode draw zum Zeichnen und bei beiden kann man die X und Y Position setzen. In diesem Beispiel wird der Sinn vielleicht noch nicht all zu klar, aber vielleicht siehst du schon, dass du nun ein beliebiges TDrawable auf immer den selben Canvas zeichnen könntest. Dazu übergibst du nur noch ein TDrawable, du weißt ja dass es ein Draw hat. Diesem Draw übergibst du den Canvas auf den gezeichnet werden kann und dich interessiert es nicht ob es sich um ein TDrawableButton, TDrawablePanel oder gar ein TDrawableHastDuNichtGesehen handelt.

Genauso leicht kannst du so ein TNotifyable definieren, dass eine Nachricht annimmt. Wenn du nun ein Hauptinstanz hast, die eine Liste von TNotifyalbes verwaltet, dann müsstest du bei einem Ereignis nur jedem dieser Objekte die Nachricht übergeben...

Hoffe du siehst was ich meine, ist wirklich wichtig in der OOP. Kommen neue Klassen hinzu, ist dir das egal. Implementieren sie ein Interface, stellen sie mindestens diese Funktionen zur Verfügung und mehr interessiert dich dann garnicht.

Zitat von mimi:
eine frage habe ich aber noch:
verwaltung der obj.
ich möchte gerne das jedes obj z.b. ein panel sein obj. selsbt verwalten kann dies soll über ein schalter gemacht werden. d.h. wenn diese schalter auf True ist soll die eigene liste verwendet werden und wenn dierser auf False ist(standart einstellung) soll es in die allgemeine liste eingefügt werden.
Problem ist hier die umsetzung. Ein kleines beispiel währe nicht schlecht. Ich wollte wohl TObjectList nehmen..
Ich verstehe dein Frage ehrlich gesagt nicht ganz. Was heißt denn "sein obj. selbst verwalten?". Genauer gesagt was soll denn verwaltet werden? Wenn du hier so etwas wie Kinder haben meinst, da würde ich dir auch zu einer TObjectList raten. Auch zu Interfaces, wenn du hier ein Interface hast, dass ein Add und ein Remove (oder Ähnliches) bietet, dann könntest du damit leicht in jeder Klasse die dieses Interface implementiert ein Objekt hinzufügen oder entfernen.

Gruß Der Unwissende
  Mit Zitat antworten Zitat