Zitat von
Kroko1999:
ich glaube, die Klasse die die Daten hält sollte dies auch verarbeiten oder ?(
OOP)!
Äh, lustige Idee, wie kommst du denn darauf? Nehmen wir mal ein Integer, hält auch ein Datum (auch ohne
OOP, wer auf 'ne Klasse besteht baut sich halt einen Wrapper). Ok, wird nur von der
Unit in der Integer definiert ist mit dem gearbeitet? Wohl kaum.
Was
OOP angeht, so wird eine Klasse immer so aufgebaut, dass sie nach aussen wohl definierte Schnittstellen hat. Man überlegt sich in einem sehr abstrakten Modell, welche Klassen wie miteinander interagieren müssen.
Es gibt dabei allerdings kein richtig oder falsch, es variiert stark mit dem Betrachter und Problem, wie die Klassenstruktur aussieht.
Das ist auch erstmal alles was man tun sollte, man überlegt sich nur, was von welcher Klasse auch von aussen Sichtbar sein muss. Es geht hier auch wirklich nur um Methoden und Properties (Variablen sollten nie direkt sichtbar sein). Natürlich weiß man was eine Methode leisten soll, aber wie sie das macht, gehört noch nicht in das Design. Die Überlegung ist nur, was muss die Methode kennen / als Parameter bekommen.
Daraus kann man dann leicht abstrakte Klassen oder Interfaces erstellen. Von diesen leitet man dann etwas Konkretes ab (implementiert Interfaces). Damit hat man auch maximale Wiederverwendbarkeit, da man nur die konkrete Instanz tauschen muss. Aber das ist ein anderes Thema, findet ihr bestimmt ne Menge in der
DP zu.
Zu dem hier geschilderten Problem, es hat denke ich weniger etwas mit
OOP zu tun. Es geht nur um etwas mehr Überblick. Es wird sicherlich ein Hauptklasse geben, in der die Instanzen der Daten erzeugt werden. Ok, moment, ich führ einfach mal der Übersicht halber ein paar neue Namen ein. Klasse 1, 2 und 3 ist nicht gerade das wahre (sorry).
Also, sagen wir, wir haben eine Klasse TDaten. Diese bietet die Möglichkeit Daten zu speichern und die auch wieder auszugeben.
Dann haben wir eine Klasse TVearbeitung. Diese kennt die Klasse TDaten und kann diese Daten verarbeiten.
Als letztes bleibt eine Klasse TVerwaltung. Diese kennt alle Möglichkeiten der verarbeitung und die kennt auch alle Daten.
Jetzt gibt es mehrere Möglichkeiten wie diese Klassen interagieren könnten. Wie vielleicht schon gesehen wurde, habe ich hier eine andere Sichtweise genommen. Die Klassennamen sind nicht ganz ohne Bedacht gewählt, denn eure Klassenstruktur sieht sicherlich noch häufiger so aus. Man hat eine Zentrale Verwaltung, die muss (fast) alles kennen. Man hat einen Datentypen (analog für mehrere, von dem jeder einzeln betrachtet wird). Dieser Datentyp muss in der Verwaltung bekannt sein, da diese ihn verwaltet. Aber dieser Datentyp muss nicht wissen wie er verwaltet wird.
Dann bleibt noch die Verarbeitung. Diese muss wissen was für einen Datentypen sie bekommt, denn sie arbeitet auf diesem Datentypen. Der Datentyp muss aber nichts von der Verarbeitung wissen. Damit kann man auch ganz verschiedene Verarbeitungen für einen Datentypen entwickeln.
Die Verwaltung kennt wiederum die Verarbeitungsmöglichkeiten, aber auch hier ist die andere Richtung nicht nötig.
Nochmal zusammengefasst:
- Datentyp : Muss ein Datum speichern und zurückgeben können
[*}Verarbeitung : Bekommt etwas vom Typ Datentyp, verarbeitet es
- Verwaltung : Erzeugt Instanzen vom Datentyp und lässt sie durch die Verarbeitung verarbeiten
Ist kein schönes oder Vollständiges Modell, aber ein einfaches. Natürlich könnte auch die Verarbeitung Instanzen erzeugen,...
Hier kennt jeder Punkt immer nur die über ihm Liegenden und das reicht auch.
Damit solltest du alles haben was du brauchst, noch mal als Beispiel:
Delphi-Quellcode:
// Unit 1
type
TDatentyp =
class(TObject)
private
// Variablen können immer privat sein
FValue : Integer;
protected
function getValue : Integer;
procedure setValue(
const Value : Integer);
public
property Value
read getValue
write setValue;
end;
// getValue und setValue dürfte klar sein
Delphi-Quellcode:
// Unit 2
// uses Unit 1;
type
TVerarbeitung =
class(TObject)
public
procedure doFoo(
const Data : TDatenTyp);
end;
procedure TVerarbeitung.doFoo(
const Data : TDatenTyp);
begin
// verdoppelt den in Data gespeicherten Wert
if assigned(Data)
then
begin
Data.Value := Data.Value * 2;
end;
end;
Delphi-Quellcode:
// Unit 3
// uses Unit 1, Unit 2;
type
TVerwaltung =
class(TObject)
private
Datum : TDatenTyp;
Verarbeitung : TVerarbeitung;
protected
public
constructor create;
destructor destroy;
override;
procedure setDatum(
const Value : Integer);
procedure doubleValue;
end;
constructor TVerwaltung.create;
begin
self.Datum := TDatenTyp.Create;
self.Verarbeitung := TVerarbeitung.Create;
end;
destructor TVerwaltung.destroy;
begin
self.Datum.Free;
self.Verarbeitung.Free;
end;
procedure TVerwaltung.setDatum(
const Value : Integer);
begin
self.Datum.Value := Value;
end;
procedure TVerwaltung.doubleValue;
begin
Verarbeitung.doFoo(self.Datum);
end;
Ja, auch hier gilt, ist kein schönes Beispiel, aber ich hoffe es macht die herangehensweise klarer. Wenn Verarbeitung deiner Klasse 3 entspricht und Verwaltung der Klasse 1, dann muss 3 die 1 nicht mehr kennen. 3 Bekommt nur irgendwas vom Typ Klasse 2 und arbeitet damit. Wen dieser Verarbeitete Wert interessiert und wo die Instanz von Klasse 2 herkam, dass alles muss Klasse 3 nicht wissen. Es muss nur ein Parameter vom richtigen Typen übergeben werden, der ist dann natürlich bekannt.
Das ganze sieht auch rein imperativ nicht anders aus.
Es hat also nicht wirklich etwas mit
OOP zu tun. Aber andererseits ist es insbesondere (auch) in der
OOP eine Vorschrift, dass niemand mehr sieht als er muss. Keine Sorge, gutes Design der Klassen (oder Programme) bringt einem die Erfahrung. Designfehler passieren jedem mal. Sie kosten nur unterschiedlich viel. Je früher du sauber planst, desto geringer die kosten (am Anfang/ privat nur Zeit, später recht viel Geld).
Gruß Der Unwissende