![]() |
Warum und wann eine Klasse benutzen
Ich habe recht einfache doch zugleich schwere Frage.
Ich programmiere in Delphi schon eine Weile, immer ein bisschen dazu gelernt. Nun, scheine ich an einen Punkt angelangt zu sein wo mich das Ganze etwas genauer interessiert. Ich habe nie aus den Büchern gelernt, immer nur gelesen , probiert und mir die Sachen zu Recht gebastelt. Mit dem Verständnis kamen Fragen auf. (Leider habe ich sehr viele Grundbegriffe verschlafen, bzw. ignoriert) Heutige Frage sind Klassen. Wie man Sie erstellt weiß ich schon. Ich verstehe auch wie man damit umgehen kann/soll Meine Frage ist. Wann ist es sinnvoll die zu benutzen oder grob gesagt, wozu sollte ich Sie benutzen. Ich schreibe keine große Projekte, bin nur ein Hobby-Programmierer. Ich habe recht viel über Klassen schon gelesen, so eine Erklärung findet man aber schlecht. Es wäre nett wenn mich ein Profi aufklären könnte. Ich brauche nur den Sinn der dahinter steckt. |
AW: Warum und wann eine Klssse benutzen
Das ist ein reichlich großes Faß. ;-)
Es nennt sich "Objekt-Orientierte Programmierung" (OOP). Im Kern geht es darum, Grenzen zu ziehen. Zum Einen schon in der Struktur Deines Programmes, zum Anderen in einer klaren Aufgabenteilung und des Weiteren in einer klaren Aufteilung von Informationen - wer wo und wie auf etwas zugreifen darf oder eben nicht. Hast Du Dir mal einen Artikel über OOP im Allgemeinen durchgelesen? Wenn nicht, solltest Du das jetzt tun - und sei es bei Wikipedia. Danach können wir über diverse Fragen sprechen. Aber das Grundwissen, das Für und Wider, solltest Du Dir selbst aneignen. |
AW: Warum und wann eine Klasse benutzen
Vielleicht etwas Laien-näher (fällt mir leichter ;-)):
Mit Records kannst Du Daten verwalten und per Programmcode auf diese zugreifen. Hast Du Personendaten mit Geburtsdatum und willst das Alter berechnen musst Du dafür irgendeine (externe) Funktion aufrufen. Mit Klassen kannst Du Daten und dazugehörigen Code an einer Stelle definieren. Du kannst dann direkt Person.Alter verwenden oder Person.VerheiratenMit(AnderePerson) aufrufen. Instanzen von Klassen sind Objekte. Die haben Daten und Fähigkeiten und können leicht weitergeben und verarbeitet werden. Wenn man die gesamte Funktionalität einer Anwendung im Programmcode abbilden will und zur Datenverwaltung lediglich verschiendene Records hätte, wäre das unheimlich kompliziert. In OOP haben die Objekte sozusagen ein Eigenleben, das man gleich benutzen kann. So ist z.B. ein Button (auch ein Objekt) in der Lage, sich selbst zu zeichnen und auf einen Klick zu reagieren und ein Timer hat die Fähigkeit, innerhalb bestimmter Zeiten eine Ereignisbehandlung aufzurufen. Stell Dir vor, Du müsstest bei jeder möglichen Mausaktion den Button gedrückt oder ungedrückt SELBST neu zeichnen oder willst in einer Anwendung ohne TTimer jede Sekunde die Formularfarbe ändern lassen. Das ginge zwar notdürftig, wäre aber EXTREM aufwendig. Klassen lassen sich auch "vererben". Dadurch kann man von bestehenden Klassen andere Klassen ableiten, die über spezialisierte Eigenschaften verfügen. |
AW: Warum und wann eine Klasse benutzen
Als ich mit die selbe Frage gestellt habe (kommt wohl irgendwann bei jedem ;-) ) habe ich folgende Vorteile gesehen:
Wichtig: Das Thema Klassen und OOP ist mit den Vorteilen die ich hier nenne bei weitem nicht behandelt, soll Dir nur einen Anhaltspunkt geben: - Wiederverwendbarkeit von Code - Bei Wiederverwendung brauchen Änderungen nur einmal gemacht werden - Abgrenzung und Trennung von Logik und Oberfläche - Zwingt zum saubereren Programmieren - Zugriff und Veränderbarkeit von "Werten" können besser geregelt werden - Ermöglicht eine bessere Strukturierung und Wartbarkeit des Programms |
AW: Warum und wann eine Klasse benutzen
Wie Daniel schon sagte: OOP ist das Stichwort, wenn du Klassen verstehen willst.
Dahinter steckt (im Großen und Ganzen) weniger eine bestimmte Methode als eine bestimmte Sichtweise auf Programme, ein ![]() Man programmiert nicht nur in Objekt-orientiert, sondern man denkt Objekt-orientiert. Ein Vorteil für Einsteiger in OOP ist, dass es sich relativ gut eignet um reale Gegenstände zu beschreiben. Das ist allerdings nur der Anfang; reale Gegenstände reichen nicht aus, auch Konzepte und Verfahren können in Klassen gegossen werden. Um OOP zu verinnerlichen, solltest du Gedankengänge anderer Programmierer nachvollziehst. Anfangs in Tutorials zu Klassen, dann in Bücher zu OOP* und später Pattern. Es kann (fast) nie schaden, Code anderer Programmierer zu lesen und sich an Diskussionen zu Lösung von Entwurfs-Problemen in Foren zu beteiligen. * Adhoc fällt mir da keines ein; vielleicht hat da jemand ein wirklich gutes im Schrank stehen. |
AW: Warum und wann eine Klasse benutzen
Zitat:
![]() Kurzer Artikel: ![]() |
AW: Warum und wann eine Klasse benutzen
Zitat:
![]() Das Buch ist Top und es steht sogar im "Neuland" Internet :thumb: |
AW: Warum und wann eine Klasse benutzen
Keine Ahnung ob ich meine Frage falsch formuliert habe, oder nicht Jeder es auf mein Art interpretiert hat.
Am besten kann ich mit dem Tip von Darlo umgehen. Ein Dank eigentlich an Alle beteiligten, TiGü aber besonders, das wäre im Zusammenhang mit anderen Antworten die beste Lösung. Nun, etwas klarer. Ich weiß was KLassen sind, ich weiß auch was OOP bedeutet. Die Frage war , was es bringen soll. Nun, Vererbung ist gut und schön, bei kleinen Projekten aber unbedeutend. Grob gesagt zu jetzigem Zeitpunkt würde ich behaupten. Warum sollte ich mich um den Speicher kümmern, Werte vererben wenn es auch ohne geht. Natürlich ist mir klar dass es falsch ist. Die Frage war bezogen auf WARUM. Was bringt es in einem "Hallo World" Tool, den Wert einer Box in eine Klasse zu verlagern, verarbeiten und zurück zu geben? Das ist zwar ein dämliche Beispiel, sollte nur wirklich als Beispiel dienen. Ab wann ist es eben sinnvoll Klassen zu benutzen. Früher habe ich etwas mehr oder weniger VB.NET programmiert. Da habe ich fast Alles in die Klasse gelegt. Allerdings nicht weil ich gewusst habe wann es Sinn ergibt, sondern weil es mir immer wieder gesagt wurde, also habe ich es auch getan. Gelernt wie Klassen funktionieren, wozu die gut sind und Sie genutzt. Ich programmiere nur Hobbymessing, meine Projekte sind auch meist klein. Trotzdem möchte ich versuchen es richtig zu machen. Viel mehr geht es eigentlich um mein Verständnis für die Sache. Leider habe ich in den ganzen Antworten nicht die meine Antwort gefunden. Ich schaue mir die Bücher an, mal schauen was dabei raus kommt. Dank geht an Alle beteiligten. |
AW: Warum und wann eine Klasse benutzen
Du meinst also etwas wie: "Warum Datenverwaltung in Klassen?"
Das muss nicht unbedingt sein. Es kann Vorteile bringen, um den Quelltext übersichtlich zu strukturieren. Man kann eben die Daten gut kapseln und über Objektzuweisungen flexibel damit arbeiten. Die Objekte "leben" so lange bis sie wieder zerstört werden. Man kann auf sie mehrfach zugreifen oder sie z.B. in Listen leicht verschieben. Records sind zwar ähnlich, aber i.d.R. etwas umständlicher im Handling. Wenn Du in einem kleinen Projekt nur 20 Variablen brauchst, dann kannst Du sie natürlich ohne Weiteres auch einfach in einer Unit definieren. Wenn das Projekt größer wird und z.B. unterschiedliche Formen der Datenspeicherung ermöglichen soll, ist man mit einer Klasse übersichtlicher dabei. (Habe ich Dich jetzt besser verstanden?) |
AW: Warum und wann eine Klasse benutzen
Zitat:
Ich hab irgendwann einen Artikel gelesen in dem über die Frage philosophiert wurde ob Klassen uns das Leben leichter machen, alternativ ob das Arbeiten dadurch schneller wird. An den genauen Wortlaut kann ich mich jetzt nicht mehr erinnern, aber aber die Antwort war in etwa: mit Klassen zu arbeiten sparrt keine Zeit im Vergleich zu der klassischen Prozeduren/Unit-Sammlungen. Ob das stimmt muss jeder für sich beantworten, es war aber die Antwort des Artikels. Deswegen würde ich die Frage nicht in die Richtung stellen. Ich persönlich bin eher der Unit-Prozedur-Sammlungen Typ, denn eine Klasse macht immer mehr Arbeit (meine Meinung) und es muss nicht immer eine Klasse sein. Trotzdem, eine Klasse ist eine feine Sache, denn sie bietet Möglichkeiten. Im Grunde ist eine Klasse zum Teil auch nichts anderes als eine Prozedur-Sammlung. Die wären dann eher die Methoden. Also Prozeduren und Funktionen einer Klasse. Dann hat die Klasse aber auch Eigenschaften. Ich beschreibe das gerne als intelligente Variablen, denn wenn ich einer normalen Variable "Zitrone", die nur grün oder gelb sein kann, die Farbe blau zuweise, juckt es sich nicht. In einer Klasse kann man den Zuweisungsprozess über eine Prozedur leiten. Das geht automatisch, so dass der Programmierer sich gar nicht drum kümmern muss. Diese Arbeit hat sich der Programmierer der Klasse gemacht. Der eigentliche Programmierer muss sich nicht mehr drum kümmern. Das kann man zwar auch mit einer normalen Variable und Prozedur oder Funktion auch machen, aber dann stellt sich die Frage: warum in dem Fall nicht gleich eine Klasse schreiben? Sie ist ja dazu gemacht solche Aufgaben zu übernehmen.
Delphi-Quellcode:
Das kleine Beispiel verdeutlicht vielleicht was ich meine. In der Prozedur Button1Click gebe ich als Zitronenfarbe blau an. Zitronenfarbe scheint eine Variable zu sein, ist aber eine Eigenschaft. Betrachtet man property Zitronenfarbe (unter Type) wird der Schreibzugriff auf die Eigenschaft an die Prozedur ZFarbe umgeleitet. Diese Prüft den Wert und übernimmt die Speicherung in FZitronenfarbe. Wird gelesen, wird direkt aus der Variable gelesen.
type
TZitrone = class private FZitronenfarbe: String; procedure ZFarbe(a: String); public constructor Create; property Zitronenfarbe: string read FZitronenfarbe write ZFarbe; end; constructor TZitrone.Create; begin FZitronenfarbe := 'gelb'; end; procedure TZitrone.ZFarbe(a: String); begin if (LowerCase(a) = 'grün') or (LowerCase(a) = 'gelb') then FZitronenfarbe := a else FZitronenfarbe := 'gelb'; end; procedure TForm1.Button1Click(Sender: TObject); var Zitrone: TZitrone; begin Zitrone := TZitrone.Create; Zitrone.Zitronenfarbe := 'blau'; ShowMessage(Zitrone.Zitronenfarbe); Zitrone.Free; end; Bei der Gelegenheit wird bei Create der Zitrone die Farbe gelb zugewiesen. Muss man also auch nicht mehr selbst machen. All das kann man zwar auch selbst mit Prozeduren und Funktionen machen, den Job übernimmt aber die Klasse für einen. Aufgaben werden sozusagen im Hintergrund erledigt. Die Entwicklung ist vielleicht mit mehr Aufwand verbunden, aber später holt man das wieder raus. Bei Prozeduren-Lösung müsste man sich selbst um alles kümmern. Das ist natürlich nur eine der Vorteile von Klassen. Eine weitere wäre zum Beispiel die Vererbung. Man kann eine bestehende Klasse nehmen und sie mit paar Klicks erweitern.
Delphi-Quellcode:
Wenn ich zum Beispiel ständig eine Bitmap mit den Massen 64 x 64 Pixel brauche und mich das ständige Wertezuweisen stört, könnte ich mir meine eigene Bitmap Klasse schreiben die bereits die richtige Abmessungen besitzt. Vererbung bietet noch mehr Möglichkeiten, aber das wäre etwas simples als Beispiel.
type
TBitmap64 = class(TBitmap) private public constructor Create; end; constructor TBitmap64.Create; begin inherited; Self.Width := 64; Self.Height := 64; end; procedure TForm1.Button2Click(Sender: TObject); var Bmp64: TBitmap64; begin Bmp64 := TBitmap64.Create; Canvas.Draw(0, 0, Bmp64); Bmp64.Free; end; Wie schon oben erwähnt, man kann auch ohne eigene Klassen programmieren, aber gelegentlich lohnt es sich Klassen zu schreiben. |
AW: Warum und wann eine Klasse benutzen
Die letzten beiden Antworten sind genau das was ich gesucht habe.
Ja @stahli genau so solltest du es verstehen. Genau derart Antworten habe ich gesucht. Ich benutze schon ziemlich lange eigene Klassen, habe mich aber nie wirklich damit beschäftigt. Nun hat es angefangen mich ernsthafter zu interessieren, und siehe da, es tauchten Fragen auf. Auch ein Dank an @Popov , sehr gut erklärt. Das sind Gründe genug um mehr über OOP zu lesen. Es ist nämlich nicht so dass es ganz neu für mich ist, nun möchte ich es aber besser und sinnvoller machen. Danke noch Mal. |
AW: Warum und wann eine Klasse benutzen
Ja, manchmal muss erst der berühmte Groschen fallen. Ich hatte mal das Problem mit begin und end bei Pascal, da ich mit dem C64, bzw. TI-99/4A Basic angefangen habe und das Basic diesen "Unsinn" nicht brauchte. Ich konnte erst weiter machen, als ich verstanden habe, dass auch Basic ein begin und end hat, nur versteckt, bzw. indirekt (siehe next bei for). Im Grunde das Gleiche in grün. Manchmal muss einfach der Groschen fallen.
|
AW: Warum und wann eine Klasse benutzen
Ein weiterer, sehr toller Aspekt an OOP ist Polymorphie. Für mich ist das vielleicht sogar der entscheidende Punkt, da man ihn im Gegensatz zu Kapselung und Vererbung eigentlich nicht gescheit ohne Klassen simulieren kann (technisch möglich ist es natürlich, ist dann aber nicht mehr wirklich eleganter als Alternativen).
Delphi-Quellcode:
type
TShape = class protected FLeft, FTop, FSize: integer; public procedure DrawTo(Canvas: TCanvas); virtual; abstract; property Left: integer read FLeft write FLeft; property Top: integer read FTop write FTop; property Size: integer read FSize write FSize; end; TCircle = class(TShape) public procedure DrawTo(Canvas: TCanvas); override; end; TSquare = class(TShape) public procedure DrawTo(Canvas: TCanvas); override; end; implementation procedure TCircle.DrawTo(Canvas: TCanvas); begin Canvas.Ellipse(Left, Top, Left + Size, Top + Size); end; procedure TSquare.DrawTo(Canvas: TCanvas); begin Canvas.Rectangle(Left, Top, Left + Size, Top + Size); end;
Delphi-Quellcode:
Mit records geht das einfach nicht so schön... vor allem nicht, wenn man später das Programm leicht um weitere Spezialisierungen erweitern können will.
type
TMyForm = class(TForm) procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormPaint(Sender: TObject); private FShapes: array[0..4] of TShape; end; implementation procedure TMyForm.FormCreate(Sender: TObject); begin // *Irgendwelche* Formen z.B. in einem Array/Liste speichern. // Konkreter Typ ist egal, solange sie nur von TShape erben. for i := low(Shapes) to high(Shapes) do begin if Odd(i) then Shapes[i] := TCircle.Create else Shapes[i] := TSquare.Create; Shapes[i].Size := i * 5; Shapes[i].Left := i * 20; Shapes[i].Top := 0; end; end; procedure TMyForm.FormPaint(Sender: TObject); begin // Wir können jetzt alle diese verschiedenen Objekte mit dem gleichen // Code verarbeiten, obwohl es sich um verschiedenartige Klassen // handelt und jeweils spezialisierter Code ausgeführt wird // -> man spart sich u.U. etliche Case-Strukturen, die den Code // sonst unübersichtlich und fehleranfällig machen würden for i := low(Shapes) to high(Shapes) do Shapes[i].DrawTo(Canvas); end; procedure TMyForm.FormDestroy(Sender: TObject); begin for i := low(Shapes) to high(Shapes) do Shapes[i].Free; end; |
AW: Warum und wann eine Klasse benutzen
Die 3 großen Stichworte zur OOP lauten Kapselung, Vererbung und Polymorphie. Kurze vereinfachte Erläuterung zu den einzelnen Stichworten:
Kapselung: Eine Klasse stellt die Konsistenz ihrer Daten selbständig sicher. Das erreicht sie dadurch, dass sie keinen direkten Zugriff auf diese gewährt, sondern lediglich über Schnittstellen in Form von Properties. Außerdem kann sie über Sichtbarkeitsebenen (private, protected, public) bestimmen, wer auf welche Daten und Methoden Zugriff haben soll. Vererbung: Wird eine Klasse von einer anderen abgeleitet, so erbt sie automatisch deren Properties und Methoden, ohne dass eine einzige zusätzliche Zeile Code nötig wäre. So lässt sich eine Klassenhierarchie aufbauen, in der die Funktionalität und/oder Spezialisierung von oben nach unten stetig zunimmt. Polymorphie: Vielgestaltigkeit, d.h. man kann z.B. einen Funktionsparameter vom Typ einer bestimmten Basisklasse deklarieren und sichergehen, dass auch davon abgeleitete Klassen dazu passen, ohne deren exakten Typ kennen zu müssen. Das klingt vielleicht etwas abstrakt, daher mal ein Beispiel:
Delphi-Quellcode:
In der Prozedur MachKrach ist ein Parameter vom Typ TTier deklariert. Es ist der Prozedur also vollkommen wurscht, ob es sich dabei nun um einen Hund oder eine Katze handelt, sie weiß aber, dass das Tier auf jeden Fall über eine Methode GibLaut verfügt, so dass sich diese über die TTier-Klasse aufrufen lässt.
type
TTier = class public procedure GibLaut; virtual; abstract; end; THund = class(TTier) public procedure GibLaut; override; end; TKatze = class(TTier) public procedure GibLaut; override; end; ... procedure THund.GibLaut; begin ShowMessage('Wuff'); end; procedure TKatze.GibLaut; begin ShowMessage('Miau'); end; procedure MachKrach(Tier: TTier); begin Tier.GibLaut; end; Man kann natürlich auf den ganzen Schmu auch verzichten, macht es sich damit aber meist unnötig schwer. Das soll aber nicht heißen, dass OOP-Programmierung nun die Lösung aller Probleme wäre, man kann auch in OOP Mist schreiben, ebenso wie man auch prozedural gute Programme hinbekommen kann, der Aufwand ist aber (zumindest bei Neuentwicklungen) um Einiges größer. P.S.: Zwischenzeitlich wurde zwar ein neuer Post geschrieben, trotzdem schicke ich das mal ab. |
AW: Warum und wann eine Klasse benutzen
Zitat:
Ansonsten schließe ich mich der Ansicht Daniels an, wonach es auf diese doch eher allgemeine Frage keine konkretere Antwort geben kann als: Lese dich ein in OOP und Klassendesign. |
AW: Warum und wann eine Klasse benutzen
Für mich liegt der merkbarste Effekt beim Verwenden von Klassen ganz naiv betrachtet darin, dass ich zusammengehörige Daten und Verhaltensweisen in einen gemeinsamen "Container" packen kann. Dies ist vor allem dann immer wieder schön, wenn ich mehrere Instanzen solcher Container brauche, die zwar alle gleich strukturiert sind und sich gleich verhalten, aber unterschiedliche Daten tragen müssen. Zudem kann ich gleich Verhaltensweisen in den Container integrieren, um die ich mich nachher nie wieder kümmern muss - ich muss mir nichtmals Sorgen darum machen, wie meine Datenstrukturen dazu auszusehen haben; die ist ja ebenfalls schon drin. (Im Gegensatz z.B. zu einer Prozedur, die dafür geschrieben ist X Werte aus Y Arrays zu verarbeiten. Hier müsste ich immer darauf achten, eben genau passende Arrays zu erstellen. Diese Art zu arbeiten wird mit zunehmender Parallelisierung lustigerweise aber schon wieder interessanter.)
Ich bin zwar mit QBASIC und TP5 aufgewachsen, habe mich aber schon so sehr an OOP gewöhnt, dass ich es mehr oder weniger als die "natürliche" Art zu programmieren empfinde. Den Eindruck fördert bei mir sicherlich auch, dass ich es leicht finde Echtwelt-Probleme in Form von Klassen und Objekten abzubilden. Ich finde, es ist einfach oft eine schon gute Terminologie für eine Fülle an Alltagsaufgaben und -Daten. Zumindest passt es oft für die Dinge, die ich zum Brötchenverdienen schreibe echt gut. Umfangreiche Hierarchien waren bislang bei mir aber nicht oft angesagt, oftmals nur um leicht underschiedliche Objekte in gemeinsamen Listen verarbeiten zu können. Entwickler von Komponenten-Suits sind da sicherlich weit mehr von betroffen. Insgesamt empfinde ich den Wiederverwendungswert bei Klassen als für höher. Zumindest so lange es sich nicht nur um einzelne kleine Helferlein in Prozedurform handelt. Diese landen bei mir oftmals dann auch gesammelt lose in einer Unit. Entscheidend für die Geschäftslogik sind davon aber kaum welche, da geht es oft um nicht mehr als z.B. Strings in gewisser Weise zentral zu formatieren o.ä. Lösbar sind bestimmt fast alle Probleme mit fast allen Programmier-Paradigmen, und je nach dem wie geübt der Programmierer darin ist auch ähnlich schnell und (für ihn) komfortabel. Ich finde es eigentlich immer nur wichtig, sich nicht auf einen Weg einzuschießen. Oft ist es nämlich die Aufweichung in andere Paradigmen, oder gar Mischung mehrerer, die einem die elegantesten Möglichkeiten eröffnen. So wie Delphi z.B. Prozedural und OOP in einer Sprache nahtlos vereint. Es ist sicherlich nicht verkehrt, sich alles mal intensiv zu beschauen, und nachher auch zu benutzen wo angebracht. Und letztlich kommt wie so oft auch eine große Protion persönlichen Geschmacks dazu. (Oder ersatzweise firmeninterne Standards ;)) |
AW: Warum und wann eine Klasse benutzen
Auch für eine "Hello World" Anwendung kann die Verwendung von Klassen hilfreich sein.
Genau dann, wenn das Ausgabeziel (MessageBox, Konsole, Drucker) dynamisch sein soll.
Delphi-Quellcode:
unit Outputter;
interface type TOutputter = class protected procedure DoOutput( const AStr : string ); virtual; abstract; public procedure Output( const AStr : string ); overload; procedure Output( const AFormat : string; AArgs : array of const ); overload; end; TNullOutputter = class( TOutputter ) protected procedure DoOutput( const AStr : string ); override; end; TConsoleOutputter = class( TOutputter ) protected procedure DoOutput( const AStr : string ); override; end; implementation uses System.SysUtils, Winapi.Windows; { TOutputter } procedure TOutputter.Output( const AStr : string ); begin DoOutput( AStr ); end; procedure TOutputter.Output( const AFormat : string; AArgs : array of const ); begin Output( Format( AFormat, AArgs ) ); end; { TNullOutputter } procedure TNullOutputter.DoOutput( const AStr : string ); begin // Nichts machen end; { TConsoleOutputter } procedure TConsoleOutputter.DoOutput( const AStr : string ); begin AllocConsole; try Writeln( AStr ); Writeln; Write( 'Press any key to continue... ' ); ReadLn; finally FreeConsole; end; end; end.
Delphi-Quellcode:
unit Outputter_VCL;
interface uses Outputter; type TMsgOutputter = class( TOutputter ) protected procedure DoOutput( const AStr : string ); override; end; TPrintOutputter = class( TOutputter ) protected procedure DoOutput( const AStr : string ); override; end; implementation uses Vcl.Dialogs, Vcl.Printers; { TMsgOutputter } procedure TMsgOutputter.DoOutput( const AStr : string ); begin inherited; ShowMessage( AStr ); end; { TPrintOutputter } procedure TPrintOutputter.DoOutput( const AStr : string ); begin inherited; Printer.BeginDoc; try Printer.Canvas.TextOut( 100, 100, AStr ); Printer.EndDoc; except Printer.Abort; end; end; end.
Delphi-Quellcode:
unit Main_FormU;
interface uses Outputter, Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls; type TMain_Form = class( TForm ) Output_RadioGroup : TRadioGroup; Hello_Button : TButton; procedure Output_RadioGroupClick( Sender : TObject ); procedure Hello_ButtonClick( Sender : TObject ); private FOutput : TOutputter; procedure SetOutput( const Value : TOutputter ); protected property Output : TOutputter read FOutput write SetOutput; public constructor Create( AOwner : TComponent ); override; destructor Destroy; override; end; var Main_Form : TMain_Form; implementation {$R *.dfm} uses Outputter_VCL; { TMain_Form } constructor TMain_Form.Create( AOwner : TComponent ); begin inherited; Output := TNullOutputter.Create; end; destructor TMain_Form.Destroy; begin Output := nil; inherited; end; procedure TMain_Form.Hello_ButtonClick( Sender : TObject ); begin // Ausgabe von "Hello World" Output.Output( 'Hello World' ); end; procedure TMain_Form.Output_RadioGroupClick( Sender : TObject ); begin // Ausgabekanal festlegen case Output_RadioGroup.ItemIndex of 0 : Output := TNullOutputter.Create; 1 : Output := TMsgOutputter.Create; 2 : Output := TConsoleOutputter.Create; 3 : Output := TPrintOutputter.Create; end; end; procedure TMain_Form.SetOutput( const Value : TOutputter ); begin if Value = FOutput then Exit; FOutput.Free; FOutput := Value; end; end. |
AW: Warum und wann eine Klasse benutzen
Danke noch Mal an Alle. Vor Allem an die super Beispiele.
Ich lerne Autodidakt, damit kann ich am meisten was anfangen. Ich analysiere es so lange bis ich es verstanden habe. Meisten funktioniert es ganz gut. (leider nicht immer) Ich bin gerade mit den Antworten etwas überlastet. Muss das Ganze erst Mal analysieren. Obwohl ich noch mit einigen Sache meine Schwierigkeiten habe, sehe ich langsam den Sinn dahinter. Tatsache ist, ich habe mir nun stark vorgenommen das Buch über OOP durchzusehen. Ich bin noch auf der Suche nach einem Buch der meiner Art zu lernen am weitesten entspricht, habe aber schon ein paar Ansätze, das hilft. Bist dato habe ich mir immer ein passende Unit gebastelt, die ich natürlich wiederverwenden konnte. Wenn man aber tiefer nachdenkt, bieten Klassen doch enorm mehr Möglichkeiten. Das einzige was ich als ERSTES in die Birne rein kriegen muss. Es sind Objekte. Den Umgang mit dem Speicher muss ich mir rein prägen. Damit tue ich mir noch etwas schwer. (unbewusst nehme ich an). |
AW: Warum und wann eine Klasse benutzen
Das kommt mir bekannt vor. ;-)
Ich habe damals (ich gleube bei Delphi 1) die Erklärung von OOP mehrfach gelesen und immer wieder gedacht: "Hää? Wie jetzt? Wieso? Hä? ... Ahhh! ... Nee? ... Ach so..." usw. Benutze einfach Objekte und globale Daten und Prozeduren und dann wirst Du mit der Zeit erkennen, wann welche Form welche Vorteile bietet. |
AW: Warum und wann eine Klasse benutzen
Eigentlich ist die Antwort ganz simpel - und zugleich sehr kompliziert.
Ich benutze mal das Beispiel, mit dem ich meinem Kollegen, seines Zeichens krasser Anfänger, die Augen öffnen konnte. Sein "Fachgebiet" damals waren MP3-Player jeder Art. Nun ist es nicht allzu schwer einen MP3-Player zu stricken. BASS.DLL rein und damit ist er schon fast fertig. Aber das ist langweilig, also verzichten wir auf die BASS.DLL und machen das alles selbst. Also schreiben wir ein paar Routinen, die DirectSound initialisieren, uns einen DirectSound-Kontext holen, Daten an DS senden und so weiter. Das sind alles Basics und wir haben dann u.a. folgende Routinen: - InitDirectSound - GetDSContext - SendToDS - CloseDSContext - FinalizeDirectSound Anschließend greifen wir uns das simple Format "WAV". Das hat einen Header und dann rohe Sounddaten. Also basteln wir weitere Routinen: - OpenWAVFile - ProcessWAVHeader - ProcessChunkofWAVData - CloseWAVFile Wesentliche Daten werden in Records gespeichert und in globalen Variablen gehalten *hust* - typisch Anfänger halt. However. Wenn das alles implementiert ist, klickt man auf "PLAY" und das zuvor selektierte WAV-File wird abgespielt. Bis hierhin haben wir den Umfang eines normalen Hobbycoder-Projektes erreicht. Und bis hierher machen Klassen auch kaum einen Sinn, das ganze geht auch mit dem Programmierparadigma "strukturiert" zu bauen. Aber nun verlassen wir diese Ebene. Wir haben plötzlich die absonderliche Idee und möchten jetzt auch MP3-Files abspielen. Im bisherigen Schema mußt du nun ALLE ROUTINEN, die sich mit Dateien befassen, ERNEUT schreiben. Also Routinen wie - OpenMP3File - ProcessMP3Header - ProcessChunkofMP3Data - CloseMP3File Selbst dann, wenn der Code völlig identisch zu dem der WAV-Files ist - natürlich könnte man sagen "okay, rufe ich einfach die WAV-Routinen auf". Kann man machen, aber dann hast du den berühmten Spaghetti-Code produziert und nach 6 Monaten fragst du dich "Hä, ich fummel hier mit MP3 herum, wieso ruf ich da nu WAV-Routinen auf ?!?". Macht man also nicht. Auch brauchst du nun alle die schönen Records ein weiteres Mal. Und die globalen Variablen. Nun hast du 2 Sätze an Routinen gebaut und mehrfach identischen Code mitsamt fast identischer Datenstrukturen produziert. Hier kommt nun OOP ins Spiel. Man bastelt sich eine Klasse namens "WAVFile". Wir schreiben uns die Methoden - OpenFile - ProcessHeader - ProcessData - CloseFile Da wir mit WAV anfangen, kann unser erster Entwurf, genauso wie oben am Anfang, nur mit WAV umgehen. Natürlich integrieren wir die Records in diese Klasse und - oha - globale Variablen sind eigentlich nicht mehr nötig. Fügen wir nun MP3 hinzu, vererben wir kurzerhand (Hier fiel vor 25 Jahren bei meinem Bruder der Groschen :-D). Wir leiten eine Klasse MP3File von WAVFile ab. Da OpenFile und CloseFile identisch für WAV und MP3 sind, brauchen wir das gar nicht mehr programmieren - Zeit, Code und Fehlersuch-Ärger gespart. Wir implementieren nur noch ProcessHeader und ProcessData und PAFF - können wir MP3, nachdem wir ein paar Anpassungen an den internen Strukturen gemacht haben. Und nun kommt OGG hinzu - nach altem Schema bastelst du nun wieder 4 Routinen und einen Satz Records, von denen wieder einiges identisch ist und du hast nun etliche Male denselben Code da stehen. In OOP leitest du wieder von WAVFile ab, schreibst nur neuen Code und hast Zeit, Code und Fehlersuch-Ärger gespart. Tja, und dann... Dann möchtest du nicht nur DirectSound unterstützen, sondern auch das brandneue Soundsystem "OpenSound". Die gleiche Leier. Ergo: In Kleinstprogrammen, wie sie Anfänger basteln und die kaum über den Umfang von 5000 Zeilen hinauskommen, wirkt OOP völlig sinnlos und produziert sogar scheinbar mehr Aufwand. Die Stärken der OOP kommen erst in größeren Projekten voll durch - und je größer und komplexer, desto effektiver ist OOP. Mein Tip: Auch wenn es sinnlos oder aufwändig erscheint - programmiere immer objektorientiert. Hast du dich erstmal an den inzwischen prähistorisch anmutenden strukturierten Stil gewöhnt, wird es irgendwann schwer, wieder auf OOP umzuschwenken. Viele, viele, viele Hobbyprogrammierer bleiben genau das: Hobbyprogrammierer, die auch nach der 50. Version ihres MP3-Players noch einen neuen anfangen und doch immer wieder dieselben Features basteln und nur die Oberfläche ändert sich. Etliche von diesen hören auch wieder auf mit dem Programmieren. Ein paar allerdings infizieren sich unheilbar mit dem Coder-Virus und womöglich bist du auch einer von diesen Irren :-D Dann sind Programme im 50k-Bereich eher das übliche Tagewerk und dann haut OOP richtig rein. |
AW: Warum und wann eine Klasse benutzen
Zitat:
Schön daß man so etwas machen kann, aber wofür ist es gut? Was bringt es mir? Wenn Olaf schreibt: Zitat:
Wenn man mit Klassen arbeitet wird das dann noch etwas einfacher, da die "Code-Organisation" etwas übersichtlicher wird. Ebenso kann man innerhalb der Klasse arbeiten wie man will, da die Schnittstellen nach draußen definiert sind und ich keine Seiteneffekte beachten muß. Schau ich mir VBA an, dann weiß ich wie OOP sich nicht präsentieren sollte, die gleiche Information in 5 verschiedenen Klassen und der Nutzer weiß nicht wofür es gut sein soll. Gruß K-H |
AW: Warum und wann eine Klasse benutzen
Zitat:
Doch wenns dann größer und komplexer wird, dann geht die Nummer mit Copy&Paste schwer in die Hose. Merkt man dann allerspätestens beim Fehlersuchen. Darum auch mein abschließender Tip. |
AW: Warum und wann eine Klasse benutzen
Wenn ich mit C&P arbeite, dann muss ich bei elementaren Änderungen darauf achten, dass ich auch wirklich alle betreffenden Stellen ändere. Das hat aber streng genommen noch nicht einmal direkt mit OOP zu tun.
|
AW: Warum und wann eine Klasse benutzen
Zitat:
Ich weiß nicht wie viel Bücher ich damals zum Thema OOP gelesen habe, aber an eines kann ich mich erinnern, so richtigen Bezug zu OOP brachte mir keiner bei. Als dann der Groschen gefallen war, stellte ich fest, dass alle Bücher sehr gut geschrieben waren. Das Problem war also weniger die Fachkompetenz der Autoren, als dass sie keine Lehrbücher schrieben konnten. Vor Jahren wollte es mal besser machen und hab ein Lehr-Tut angefangen. Damals habe ich mir viel Gedanken darüber gemacht und da Ganze versucht für absolute Anfänger zu schreiben, also keine Fachbegriffe, jedes Fitzelchen wurde nicht nur beschrieben, sondern auch der Sinn dahinter erklärt. Und viele Beispiel. Logische Beispiele die man auch in der Praxis anwenden konnte. Nur leider habe ich nach etwa 50 Seiten irgendwie die Lust verloren, denn es ist noch lange nicht fertig. Aber ausführlich wäre es geworden ;) Was ich dir daraus aber als Tipp zurück geben kann ist, wie du evtl. an die Sache ran gehen kannst: lass dich nicht von Fachbegriffen abschrecken. Sie sind wichtig, verwirren am Anfang aber. Übung macht den Meister. Stürze dich auf Beispiele. Und logisch müssen sie sein. Diese Obst ist Eltern und Banane ist Kindklasse ist zwar logisch, aber praxisfern. Schreibe Klassen die dem entsprechen was du auch sonst programmierst. Wenn du Grafik programmierst, dann schreib Bitmap Klassen. Irgendwas, was du schon mal als Unit gemacht hast. Um es (frei) mit Worten von Monkeyboy Ballmer zu sagen: Bitmap Klassen, Bitmap Klassen, Bitmap Klassen. Am Anfang ableiten und erweitern (siehe Bitmap64 Beispiel), dann eine Bitmap um Funktionen und Eigenschaften erweitern die du schon immer dran vermisst hast, wie zum Beispiel Clear Funktion, oder Hintergrundfarbe setzen, Skalierung, usw. Einfach sinnvolle Erweiterungen. Denn wenn man an einem Problem arbeitet, dann sucht man auch Lösungen. Dann wälzt man auch Bücher nach Tipps in die Richtung. Wenn man stattdessen aber nur stupide Beispiele aus Büchern abtippt, erkennt man oft nicht den Sinn dahinter. Und zuletzt, nutze die vorhandenen Klassen von Delphi als Beispielpool. Einfach TStringList tippen, die Strg Taste drücken und mit der Maus drauf klicken. Und nun die Klasse studieren. Aus den vorhandenen Klassen kann man viel lernen. Die sind in der Regel gut und knapp geschrieben. Und wenn du etwas nicht verstehst, dann gezielt nach Erklärung suchen. |
AW: Warum und wann eine Klasse benutzen
Wenn man Objektorientierung wirklich grundlegend verinnerlichen will (was sehr über "es gibt Klassen, Vererbung und Instanzen" hinausgeht), hat mir persönlich am meisten gebracht, mit einer tatsächlich objektorientierten Umgebung zu arbeiten. Und das war / ist Smalltalk. Dort ist einfach alles ein Objekt. Selbst Klassen und Methoden sind Objekte. True und False sind Objekte. Keywords gibt es keine. Genausowenig Operatoren (es gibt eben nur Nachrichten). Im Vergleich dazu kann man Delphi, Java und Co wirklich bestenfalls noch als klassenorientiert bezeichnen ;)
Die Einstiegshürde war zwar durchaus nicht gerade flach, aber es hat sich für mich richtig ausgezahlt. Es schult eben einfach die Denkweise extrem, wenn das Paradigma so extrem umgesetzt ist. Und ich denke, dass ich heute auch mit Java und Co deutlich objektorientierteren Code schreibe, als ich das getan habe, bevor ich Smalltalk konnte. |
AW: Warum und wann eine Klasse benutzen
Zitat:
|
AW: Warum und wann eine Klasse benutzen
Zitat:
|
AW: Warum und wann eine Klasse benutzen
Zitat:
Ich denke nicht, "das kann ich beurteilen", sondern ich beurteile es, weil ich es beurteilen kann. Übrigens: Wenn man in öffentlichen Fachforen mitreden will, sollte man auch ein wenig Gegenwind vertragen können und nicht gleich losheulen, sobald man kritische Stimmen vernimmt. |
AW: Warum und wann eine Klasse benutzen
Zitat:
Die Empfehlung, kurzzeitig mal mit Smalltalk zu arbeiten kann ich nur bestärken. Auch wenn man die Sprache danach nie wieder berührt, man nimmt viel mit, das sich auf Delphi gut übertragen lässt - zum Beispiel, warum und wie man Klassen verwendet. |
AW: Warum und wann eine Klasse benutzen
Frank - schalt' mal 'nen Gang runter. Sonst müssen wir Dich noch melden. *g*
Welchen Weg der Fragesteller am Ende verfolgt, bleibt - wie immer - ihm überlassen. Meine Güte nochmal ... das kann doch nicht so schwer sein, auch mal eine andere Ansicht neben der eigenen stehen zu lassen, selbst wenn beide nicht deckungsgleich sind. |
AW: Warum und wann eine Klasse benutzen
... außerdem scheint hier alles gesagt zu sein!
* * * C L O S E D * * * |
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:28 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz