|
Antwort |
Registriert seit: 14. Aug 2005 1.859 Beiträge Delphi 11 Alexandria |
#1
Hallo,
ich möchte einige Fragen zu OOP stellen. Mein Problem: Ich habe eine große Anzahl von Routinen für die OLE-Automatisierung von Excel, sowohl frühe Bindung als auch späte Bindung. Diese Routinen liegen als einzelnen Routinen vor und ich würde sie gerne auf OOP umstellen, grade weil sich einige Sachen in EXCEL 2007 und Delphi 2009 geändert haben. Da ich mit der strukturierten Programmierung groß geworden bin, fällt es mir relativ schwer, vernünftige Klassen für meine Programmierprobleme zu erstellen. Ich würde das Gerne mal an den Beispiel von EXCEL erklärt bekommen, wie man am sinnvollsten die Klassen aufbaut. Excel ist ja selber in Objekten aufgebaut sie bestehen ganz Grob aus folgenden:
Code:
Wie soll man nun am sinnvollsten die Klassen in Delphi nachbauen?
Application (Die Excel-Applikation)
Workbook(s) (Arbeitsmappen) WorkSheet(s) (TabellenBlätter) Row(s) (Zeilen) Column(s) (Spalten) Range und Cells(Bereiche und Zellen) Es gibt ja Abhängigkeiten zwischen den Klassen: z.B. ohne eine Application kann ich kein Workbook verwenden, ohne Application und Workbook kann ich kein WorkSheet verwenden usw. Es gibt gleiche Methoden die in den verschieden Objekten in Excel vorkommen, z.B.: die Methode Activate. Workbooks.Activate WorkSheets.Activate Range.Activate usw. Wie sollen diese am sinnvollsten in den Klassen untergebracht werden? Gibt es ein gutes Buch das Beschreibt „vom Problem zur Class mit Delphi“ und dabei auf die Eigenheiten von Delphi im Bezug auf die Klassenerstellung eingeht? Bis bald Chemiker
wer gesund ist hat 1000 wünsche wer krank ist nur einen.
|
Zitat |
Registriert seit: 13. Dez 2003 Ort: Berlin 1.756 Beiträge |
#2
Hi,
an sich ist es recht schwer Deine Frage "korrekt" zu beantworten. Wie auch bei der strukturierten Programmierung gibt es bei der Objekt Orientierung (OO) keine eindeutigen Lösungen bzw. Lösungsansätze. Vielmehr können verschiedene Wege gewählt werden, welche für unterschiedliche Lösungen auch unterschiedlich gut geeignet sein dürften. An sich versucht man beim OO - Ansatz vorallem den intuitiven Ansatz zu verfolgen. Häufig wirst Du hier den Hinweis finden, dass die OO versucht die Natur nachzubilden. An sich ist es wichtig, dass Du verstehst, was eine Klasse sein soll. Während die strukturierte Programmierung sehr strikt zwiscchen Variablen und Methoden trennt, geht die OOP einen gänzlich anderen Weg. Hier wird zusammengefasst, was zusammen gehört. Um hier auf das Beispiel mit der Natur zurück zu kommen, man klassifiziert. Der Begriff der Klasse ist entspricht nahezu dem, was Du aus der Biologie kennst. Es gibt z.B. die Klasse der Säugetiere, die der Primaten, die der Affen, die der Gorillas, die der Berggorillas, ... Während man in der Biologie wohl auch Arten, Gattungen, Familien, usw. unterscheidet würde man all das in der Informatik immer nur als Klasse bezeichnen. Eine Klasse fasst also eine bestimmte Menge von Eigenschaften zusammen. Spreche ich von einem Säugetier, dann wird es sicherlich Lungen besitzen (kenne zumindestens keines ohne), Sauerstoff atmen und natürlich seine Kinder säugen. Eine speziellere Klasse sind dann die Meeressäuger oder die Landsäuger, die eben alle Eigenschaften haben die schon ein Säugetier besitzt, zusätlich aber eben im Meer oder an Land leben. Wichtig ist es diese Hierachie im Hinterkopf zu behalten, sie bietet einen der Vorteile der OOP. Verlangst Du ein Säugetier, so ist es Dir erstmal egal, ob es sich hier um einen Gorilla oder den Schwertwal Willy handelt. Auf beide dürfte die Bezeichnung Säugetier zutreffen (auch wenn es sich um völlig unterschiedliche Exemplare handelt!). Eine Klasse ist in erster Linie also eine Art Bauplan. Da stehen die Eigenschaften drin, die alle Exemplare dieser Klasse besitzen. Über Vererbung kann man dann beliebig speziell werden (Säugetier -> Meersäuger -> Wal -> Schwertwal -> ... -> Willy). Von links nach rechts kommen nur neue, speziellere Eigenschaften hinzu, wobei keine verloren geht. Willy ist ein konkretes Exemplar, den gibt es dann auch wirklich. Der Rest ist eher abstrakt und man kann halt sagen, dass Willy ein Wal, ein Schwertwal oder eben auch ein Säugetier ist. Beim OO - Design überlegst Du dir also erstmal, was für Komponenten Du hast und wie deren Eigenschaften aussehen. Deine Problemlösung zerlegst Du dabei immer in die unabhängigen Teillösungen (so wie man immer rangeht) und fässt hier immer dass zusammen, was wirklich zusammen gehört. Du hast eigentlich schon eine gute Vorgabe gemacht. So gibt es Zellen, die haben bestimmte Eigenschaften (die gelten für jede Zelle einzeln), z.B. könnte das der enthaltene String sein oder halt auch seine Formatierung. Ebenso gibt es dann Zeilen und Spalten, die setzen sich aus Zellen zusammen. Ein Stylesheet wiederum setzt sich aus Zeilen und Spalten zusammen, hat sicherlich auch einen Titel usw. Eine Excel-Datei wiederum umfasst all das. Alles was hier also genannt wurde hat recht individuelle Eigenschaften und kann entsprechend in eine eigene Klasse gepackt werden. Schwierig (das kommt mit der Erfahrung) ist jetzt noch die Abstraktion, wo man Dinge allgemein zusammenfasst und dann eben spezieller vererbt / ableitet. Dazu musst Du immer schauen, was man einfach und sinnvoll wiederverwenden kann. Das ist wie gesagt nicht immer leicht und der Blick schärft sich mit der Erfahrung. Wenn Du eine Excel - Datei nimmst, dann ist es halt leicht zu übersehen was Du da schon hast. So siehst Du eine offene Datei, gehst Du hier ins Detail, setzt die sich eben aus den genannten Komponenten zusammen, die eigene Probleme lösen. Die kannst Du halt bis auf Zellen runterbrechen (auch der Inhalt einer Zelle könnte eine eigene Klasse sein, z.B. die Klasse Formel, wenn eine Formel enthalten ist). Je abstrakter Du modellierst, desto einfacher sind später die Möglichkeiten der Anpassung. Wie bereits gesagt, ein Wal ist ein Säugetier, alles was ich mit Säugetieren machen kann, kann ich halt auch mit Walen machen. Wale haben aber spezielle Eigenschaften, die ein Elefant nicht hätte. So ähnlich sieht es dann auch mit Excel Dateien aus. Du kannst bestimmte Probleme einfach für Excel - Dateien lösen. So haben Excel - Dateien eben Sheets, die sich aus Zellen zusammensezten. Eine Zelle kann über ihre Position angesprochen und der Inhalt gesetzt / ausegelesen werden. Ebenso kannst Du eine Excel - Datei laden oder speichern. Das ist jetzt aber sehr allgemein und abstrakt. Wie man tatsächlich eine Zelle manipuliert oder eine Datei öffnet kann ziemlich stark variieren. Intuitiv kannst Du hier Eigenschaften finden, die für eine Excel 2003 Tabelle gelten, die Du so auch für eine Excel 2007 Tabelle findest. Trotzdem werden die total unterschiedlich geladen und intern verarbeiet. Das was die gemeinasm haben steckst Du einfach in eine abstrakte Klasse oder ein Interface. Aus diesen leitest Du dann die spezielleren Klassen ab (die haben alle Eigenschaften / Methoden der abstrakten Klassen / des Interface). Ableiten heißt, dass Du zwar einen Funktionsumfang garantierst, die tatsächlich Umsetzung bleibt aber verborgen und kann leicht ausgetauscht werden. So, nun mal etwas praktischer am Beispiel, dann verstehst Du das auch sicher besser: Problem, man möchte eine Excel - Datei laden. Wie bereits gesagt, es gibt Excel 2007 Dateien und Excel 2003 Dateien, die unterschiedlich aufgebaut sind (XML vs. binär - Format). Allgemein / abstrakt würdest Du einfach eine Excel - Datei öffnen wollen, im speziellen möchtest Du das jeweilige Format öffnen. In der OOP würdest Du also erstmal ganz abstrakt modellieren
Delphi-Quellcode:
TExcelFile ist jetzt irgendeine Repräsentation des geöffneten Files. Wichtig ist hier, dass Du eine abstrakte Klasse hast. Die gibt einfach nur vor, dass eine TExcelFileLoader Klasse eine Methode openFile besitzt, die eben genauso aussieht. Da die Klasse aber abstrakt ist, kennst Du hier noch keine Implementierung. Entsprechend kannst Du auch kein Exemplar erzeugen, die Methode ist ja schließlich nicht implementiert.
TExcelFileLoader = abstract class(TObject)
public // Methode zum Laden einer Excel - Datei function openFile(const path: String): TExcelFile; virtual; abstract; end; Die tatsächliche Implementierung findet erst in den jeweiligen Ableitungen fest.
Delphi-Quellcode:
Hier hast Du nun zwei verschiedenen Implementierungen der Methode openFile. Ok, soweit ist das erstmal ziemlich umständlich, immerhin hättest Du auch einfach zwei Funktionen definieren können, wobei eine eben 2007er Dateien öffnet und die andere 2003er. Wo also ist der Vorteil der OOP?!
TExcel2007FileLoader = class(TExcelFileLoader)
public // Methode zum Laden einer Excel - Datei function openFile(const path: String): TExcelFile; override; end; TExcel2003FileLoader = class(TExcelFileLoader) public // Methode zum Laden einer Excel - Datei function openFile(const path: String): TExcelFile; override; end; ... implementation function TExcel2003FileLoader.openFile(const path: String); TExcelFile; begin // Spezieller Code zum öffnen der 2003er Dateien end; function TExcel2007FileLoader.openFile(const path: String); TExcelFile; begin // Spezieller Code zum öffnen der 2007er Dateien end; Nun ja, mehrfach viel schon das Wort abstrakt, so auch jetzt. Durch die Abstraktion ist eben die Implementierung austauschbar. Du kannst einfach eine Klasse schreiben, welche Dir ein TExcelFileLoader zurückgibt. Was wir über ein TExcelFileLoader wissen ist, dass der eben die Möglichkeit besitzt ein Excel - File zu öffnen, was der dabei macht wissen wir nicht (ist ja abstrakt). Am ehesten nimmt man wahrscheinlich eine Fabrik:
Delphi-Quellcode:
Wenn Du nun also eine Excel - Datei laden möchtest, dann ist für Dich erstmal unwichtig, was für einen TExcelFileLoader du wirklich bekommst. Du übergibst das Suffix der Datei und bekommst einen ExcelLoader, der die Datei öffnen kann
TExcelFileLoaderFactory = class(TObject)
public class function getExcelFileLoaderBySuffix(const suffix: String): TExcelFileLoader; end; ... implementation class function TExcelFileLoaderFactory.getExcelFileLoaderBySuffix(const suffix: String): TExcelFileLoader; begin if (LowerCase(suffix) = '.xls') or (LowerCase(suffix) = 'xls') then begin result := TExcel2003FileLoader.create(); end else if (LowerCase(suffix) = '.xlsx') or (LowerCase(suffix) = 'xlsx') then begin result := TExcel2007FileLoader.create(); end else // Fehlerbehandlung end;
Delphi-Quellcode:
Was hier wichtig ist, ist die Tatsache dass Du nichts mehr über das zurückgegebene TExcelFileLoader Exemplar wissen musst. In XYZ weißt Du nur von TExcelFileLoader und TExcelFileLoaderFactory. TExcel2003- und TExcel2007FileLoader brauchst Du hingegen nicht zu kennen. Entsprechend können die beliebig ersetzt werden. Kommt z.B. Excel 2011 heraus und besitzt ein total neues Format, so kannst Du den ganzen Code, beibehalten der auf die geöffnete Datei zurückgreift und die Datei öffnet. Du erstellst nur eine weitere Implementierung von TExcelFileLoader, die eben in der Lage ist dieses Format in Deine Repräsentation zu überführen und "registriest" diese in der Factory - Klasse, fertig. Alle Programme, die eben auf die Fabrik zurückgreifen können danach auch Excel 2011 - Dateien verwenden. procedure XYZ.loadFile(const Path: String); var suffix: String; ExcelFileLoader: TExcelFileLoader; begin // irgendwie das suffix ermitteln suffix := self.extractSuffix(path); // Exemplar der Klasse TExcelFileLoader erzeugen ExcelFileLoader := TExcelFileLoaderFactory.getExcelFileLoaderBySuffix(suffix); // verwenden with ExcelFileLoader.openFile(path) do begin ... Free; end; // aufräumen ExcelFileLoader.Free; end; Der krasse Gegensatz dazu wäre der direkte Aufruf einer speziellen Methode für jedes Format. Hättest Du also die Funktionen open2003File und open2007File verwendet, müsstest Du nun überall eine weitere Funktion namen open2011File einfügen, in jeder Unit, welche eine Excel-Datei öffnen können soll. Das ist unübersichtlich, aufwendig und fehleranfällig. Die OOP kann somit den Ansatz zentralisieren und erlaubt den einfacheren Austausch gegen verschiedene Varianten (z.B. auch gegen schnellere oder fehlerkorrigierte Versionen). So, nochmal zusammenfassend, alles was zusammengehört solltest Du auch zusammengehörig modellieren. Hier kannst Du sehr allgemein anfangen und Dich ins Spezielle vorarbeiten. Eine Klasse beschreibt dabei nur die gleichartigen Elemente, ein Exemplar ist etwas konkretes, was diese Eigenschaften besitzt (aber auch einen eigenen Zustand besitzt). Verhalten oder Implementierungen, die sich mehrere Klassen teilen kann man in eine gemeinsame Basisklasse stecken, Eigenschaften die sich unterscheiden kommen in die Ableitungen. Gemeinsamer Code kann bereits in der Basisklasse implementiert werden, gleiche Methoden mit unterschiedlichem Verhalten werden in der Basisklasse als abstrakt markiert und müssen entsprechend in den Ableitungen implementiert werden. Individuelle Eigenschaften gehören hingegen auf die Hierachiestufe, auf der sie für alle untergeordneten Klassen gilt! Besten Gruß, Der Unwissende |
Zitat |
Registriert seit: 14. Aug 2005 1.859 Beiträge Delphi 11 Alexandria |
#3
Hallo Der Unwissende,
erst mal Danke für die sehr ausführliche Antwort. Ich habe ja schon einige Gehversuche in OOP unternommen, aber meistens endet es damit, dass ich eine riesige sehr unübersichtliche Mammut-Class bekomme. Die meisten Schwierigkeiten bereiten mir die Schnittstellen von einer Klasse zu anderen. Ich will das mal an einem Beispiel verdeutlichen: Ich konstruiere eine OLEBasisClass die in der Lage ist verschiede OLE-Applikationen zu starten. Das ist sozusagen das Grundgerüst was alle unter const aufgeführten Applicationen gemeinsam haben.
Delphi-Quellcode:
Davon abgeleitet habe ich nun eine nur für Excel abgeleitet Klasse.
const
coEXCEL= 'Excel.Application'; coWORD= 'Word.Application'; coOUTLOOK= 'Outlook.Application'; coIE= 'InternetExplorer.Application'; type TOLEObj= Class(TComponent) private FOleVarObj: OLEVariant; FOleObjGestartet: Boolean; FOleObjVisible: Boolean; function OleObjAktive(strApplicationsName: String): boolean; function getFOleObjGestartet: Boolean; procedure setFOleObjGestartet(const Value: Boolean); function getFOleObjVisible: boolean; procedure setFOleObjVisible(const Value: boolean); function GetFOleVarObj: OleVariant; public Constructor Create(AOwner: TComponent; OleApplication: String); virtual; Destructor Destroy; override; property OLEObjStart: Boolean read getFOleObjGestartet write setFOleObjGestartet Default TRUE; property Visible: boolean read getFOleObjVisible write setFOleObjVisible Default TRUE; property OLEInstanc : OleVariant read GetFOleVarObj; End;
Delphi-Quellcode:
Im eigentlichen Programm wird Excel dann z.B: so aufgerufen:
type
THPLExcel= Class(TOLEObj) private FExcelVersion: String; Public Constructor Create(AOwner: TComponent); Destructor Destroy; override; procedure schreiben(Zeile, Spalte: Longint; Text: String); End; implementation uses Windows, SysUtils; { HPLExcel } constructor THPLExcel.Create(aOwner: TComponent); begin inherited Create(aOwner, coEXCEL); end;
Delphi-Quellcode:
Was jetzt überhaut nicht dabei ist sind zum Beispiel die Workbooks als eigene Klasse. Die Funktionen sind alle unter der THPLExcel-Class mit untergebracht.
procedure TfrmHPLExcelKomponenteDemo.Button1Click(Sender: TObject);
var aExcel: THPLExcel; begin aExcel := THPLExcel.Create(self); try try aExcel.Visible:= TRUE; finally aExcel.Free; end; except on E: Exception do begin MessageDlg(E.Message+#13+#13+'Excel ist nicht gestartet', mtError, [mbOK], 0); end; end; end; Mir ist immer noch nicht klar, wie diese sagen wir mal Unterklassen von Excel entwickelt werden sollen und diese dann in THPLExcel-Class aufgerufen werden sollen. Oder, ist der ganze Ansatz falsch und man fängt zuerst mit der Zelle an weiter zum WorkSheet usw. und arbeitet sich weiter bis zur Excel-Application vor? Bis bald Chemiker
wer gesund ist hat 1000 wünsche wer krank ist nur einen.
|
Zitat |
Registriert seit: 9. Jun 2002 Ort: Saarland 7.554 Beiträge Delphi 8 Professional |
#4
Angeblich benutzt jeder OOP und es kommen kaum Antworten ? Es ist entsetzlich.
OOP dürfte wohl kalr sein, aber wie nutzt man das richtig ? Zuerst sucht man sich mal den am Besten geeigneten Vorfahren für das Vorhaben. Da kommt bereits das erste große Du leitest alles von TComponent ab, es wird also quasi nichts Vorhandenes weiterverwendet. Du fängst also bei Null an. Das nächste wäre die Suche nach Gemeinsamkeiten, damit das Ganze einen Sinn hat. Da kommt das nächste Was hat Excel, Word und Outlook gemeinsam ? Ich denke sehr wenig. Dass diese Programme alle zufällig im MS-Officepaket sind spielt keine Rolle. Was soll man nun da überhaupt mit OOP besser machen ? Vielleicht könnte man für ein Word-Dokument und eine Excel-Arbeitsmappe irgendwas mit Öffnen, speichern etc. vereinheitlichen ? Kenne den OLE-Krempel jetzt allerdings zu wenig. Mein Vorredner hat das ja schön gezeigt mit diversen Excel-Versionen. Ich will mal noch anhand einer Komponente zeigen, wie das auch geht (stark vereinfacht) : es soll ein Edit-Feld her, in welches man nur Zahlen eingeben kann und davon abgeleitet soll noch eins erzeugt werden, welches einen DecimalSeparator zulässt. Man hat dann schonmal zumindest die Standardeigenschaften, also Keypress, Mausereignisse etc. vordefiniert. Wenn ich jetzt da nur zulasse, Zahlen einzugeben, dann muss man ja nur das OnKeyPress behandeln.
Delphi-Quellcode:
Das override braucht man, damit das "eigene" OnKeyPress verwendet wird, anstatt des standardmässigen. Es ist protected deklariert, damit danach auch noch die real-Eingaben damit erledigt werden können.
TZulZeichen = set of char;
... TIntEdit = class(TEdit) protected procedure KeyPress(var Key: Char); override; property ZulZeichen: TZulZeichen read FZulZeichen write SetZulZeichen; published ... end; Und das sieht dann so aus:
Delphi-Quellcode:
Das inherited widerspricht zwar scheinbar dem override, aber das Editfeld soll sich ja schon im Grunde so verhalten, wie ein TEdit. Schließlich zeigt es die Eingaben an, hat ein OnEnter etc. Hinzu kommt lediglich die Einschränkung auf Zahlen. Der Vorteil liegt eben hauptsächlich darin, an einer Stelle was zu ändern und nicht an vielen. Ändere ich irgendwas an diesen Prozeduren, dann
procedure TIntEdit.KeyPress(var Key: Char);
begin inherited KeyPress(Key); if not (Key in FZulZeichen) then key := #0; end; sind sie eben überall geändert und fertig. Alternativ könnte man auch für alle betroffenen Edits diese OnKeyPress-Prozedur kopieren und einfügen. Bedeutet, dann allerdings auch im Fehlerfalle die Suche an zig-Stellen. Bei Dir sehe ich an dieser Stelle allerdings eher das Problem, dass Du versuchst Sachen unter einen Hut zu bringen, die kaum was gemeinsam haben. Da verliert OOP eventuell schnell seine Vorteile.
Gruß
Hansa |
Zitat |
Registriert seit: 13. Dez 2003 Ort: Berlin 1.756 Beiträge |
#5
Zitat von Chemiker:
Ich habe ja schon einige Gehversuche in OOP unternommen, aber meistens endet es damit, dass ich eine riesige sehr unübersichtliche Mammut-Class bekomme.
Hast Du nun eine Mega-Unit, die zig Funktionen enthält, dann zerlegst Du das ganze in mehrere Units. Klassen sind ebenso nur eine weitere Strukturierungeinheit. Besonderheit dabei, Du hast halt Exemplare. Das alles kannst Du nachbilden in der strukturierten Programmierung. So kannst Du Zellen einfach als Record anlegen und hier unterschiedliche Exemplare durch eindeutige IDs unterscheiden. Eine Klasse bringt diese eindeutige Unterscheidung einfach schon mit, jedes Exemplar enthält seinen Zustand (seine eigene Belegung der Variablen). Bei gleichem Zustand ist dann halt auch das Verhalten gleich.
Zitat von Chemiker:
Die meisten Schwierigkeiten bereiten mir die Schnittstellen von einer Klasse zu anderen.
Ich will das mal an einem Beispiel verdeutlichen: Ich konstruiere eine OLEBasisClass die in der Lage ist verschiede OLE-Applikationen zu starten. Das ist sozusagen das Grundgerüst was alle unter const aufgeführten Applicationen gemeinsam haben.
Zitat von Chemiker:
Mir ist immer noch nicht klar, wie diese sagen wir mal Unterklassen von Excel entwickelt werden sollen und diese dann in THPLExcel-Class aufgerufen werden sollen.
Oder, ist der ganze Ansatz falsch und man fängt zuerst mit der Zelle an weiter zum WorkSheet usw. und arbeitet sich weiter bis zur Excel-Application vor? Wie bereits gesagt, es gibt kein Patenrezept. Der beste Weg ist immer, dass Du erst ein Modell erstellst, welches vollständig ist. Das heißt, dass Du Dir wirklich aufschreibst (z.B. in einem Diagramm) wie Deine Zerlegung in Teilprobleme / Klassen aussieht und welche Schnittstellen die Klassen bieten. Daran kannst Du dann leicht überprüfen ob die Modellierung vollständig ist (Du alle Probleme lösen kannst). Das Modell kann dabei sehr abstrakt vorliegen, was es für Dich einfacher macht, die konkrete Implementierung ist halt egal (was durch das OO vereinfacht wird). Änderungen am Modell sind verhältnismässig einfach möglich und kosten eben wenig Zeit. Vollständiges Planen ist dabei übrigens unabhängig vom gewählten Paradigma von Vorteil! Hast Du jetzt ein solches Modell, so ist die Umsetzung entsprechend einfach. Ein anderes Problem ist dann weiterhin die Modellierung. Die kann immer nur zu einem bestimmten Problem passen. Ändern sich die Anforderungen, so kann es sein, dass sich eine andere Modellierung als geeigneter erweist. Im besten Fall wirst Du nur erweitern müssen, in der Regel kommt es aber an einzelnen Stellen auch zu Änderungen. Die typische Frage die sich stellt heißt immer, was alles in eine eigene Klasse gehört. Die beiden Extreme sind dabei die Verwendung von nur einer Klasse oder eben je einer Klasse pro Variable oder Methode. Beides führt natürlich nicht weit. Besser ist es die berühmte Mitte zwischen diesen Extremen zu finden. Das ist dabei einerseits reine Erfahrungssache und kann sich andererseits halt auch ändern. Sagen wir mal Du verwendest eine Worksheet - Klasse, welche einfach pro Zelle nur einen String speichert. Da erscheint es fragwürdig eine solche Zelle eine eigene Klasse zu verwenden. Ist die Implementierung fertig ist das schon mal super. Jetzt merkst Du aber, dass Du gerne Formatierungseigenschaften mit aufnehmen würdest, dazu gehört eine Schriftart, die Größe, die Farbe, Hintergrund, ... Wie Du unschwer merkst, der Umfang der Informationen die pro Zelle gespeichert werden ist deutlich größer als der enthaltene String. Entsprechend lohnt sich nun eine eigene Klasse. Natürlich kann man dies in dem einfachen Fall ggf. schon abschätzen, aber nicht immer ist das möglich. Kommt es zu so einer Situation, dann ist das kein riesen Problem. Was man tut ist einfach auslagern. Man erstellt eine neue Klasse TZelle, welche entsprechend diese Informationen zusmamenfasst und verwendet diese innerhalb des Worksheet. Wie gesagt, es gibt keine Vorschrift wie man alles richtig macht. Die meisten Probleme - denke ich - lassen sich durch eine ausreichende Planung umgehen. An sich solltest Du einfach erstmal versuchen die Gesamtproblematik (Excel File bearbeiten) in Teilprobleme zerlegen. So wie Du es eben intuitiv machen würdest. Die Teilprobleme kannst Du erstmal je als eine Klasse betrachten. Wenn Du einfach Dinge wie Datei, Worksheets und Zellen trennen kannst (Dir sind ja die Unterschiede bekannt), dann kannst Du die eben auch als Klasse betrachten bzw. modellieren. Die zugehörigen Eigenschaften sind eben so einfach zu erkennen. Um bei der Zelle zu bleiben, sie hat eine Position (Spalte und Zeile), eine Formatierung, einen Inhalt, ... Das alles sind die Eigenschaften die Du ins Modell aufnimmst, fertig. Natürlich kannst Du auch gleich Methoden modellieren, die z.B. eine validierung der Werte vornehmen (z.B. keine Zeile > 65535). Hast Du das Modell fertig (ohne vollständig zu überlegen wie Du das alles implementierst), dann kannst Du daran überprüfen, ob alles Anwendungsszenarien möglich sind. Ist dies nicht der Fall, solltest Du am Modell eben erkennen was fehlt und nachbessern können. Irgendwann ist dann das Modell rund und Du kannst Dein Code - Skelett daraus erstellen. Die Schnittstellen der Klassen stecken direkt im Modell und können entsprechend übernommen werden. Durch die Möglichkeit der Abstraktion und damit verbunden der Austauschbarkeit der Implementierungen kannst Du dann eben einfach mit Dummy - Implementierungen die Umsetzung (sowohl top down, als auch bottom up) beginnen und sukkzessive vervollständigen. |
Zitat |
Registriert seit: 21. Aug 2005 14 Beiträge |
#6
An einer Stelle habe ich ein Problem mit dem (ansonsten sehr gelungenen und lesenswerten!) Text aus Antwort 1:
Zitat von Der_Unwissende:
Über Vererbung kann man dann beliebig speziell werden (Säugetier -> Meersäuger -> Wal -> Schwertwal -> ... -> Willy). Von links nach rechts kommen nur neue, speziellere Eigenschaften hinzu, wobei keine verloren geht. Willy ist ein konkretes Exemplar, den gibt es dann auch wirklich. Der Rest ist eher abstrakt und man kann halt sagen, dass Willy ein Wal, ein Schwertwal oder eben auch ein Säugetier ist.
Wenn ich mir jetzt aber genau den Opel Vectra B ansehe, der beim Nachbarn vor dem Haus steht, oder eben meinen Schwertwal-Freund Willy, dann habe ich jeweils ein Exemplar einer Klasse. Obwohl der Vectra auch polymorph der Klasse Automobil zugeordnet werden kann, gibt es doch immer genau eine Klasse, von der er tatsächlich und direkt ein Exemplar ist (in Java abprüfbar mit dem speziellen Schlüsselwort "instanceof" - mein Delphi ist leider recht eingerostet...). Falls das jetzt konstruiert erscheint, so liegt das daran, dass genau an dieser Stelle die Analogie zur Realität versagt. In der Realität könnte ich meine Klassifizierung stets noch verfeinern (Opel Vectra B produziert 1999 in Herstellungswerk XY, männliche Schwertwale mit Freundschaftsbedürfnis), in der OOP ist das nicht so - es gibt nur die Klassen, die man modelliert. Wenn ich sage, beim Opel Vectra B ist Schluss mit der Hierarchie, dann ist dort Schluss. Zurück zu den Exemplaren: Im Gegensatz zu Klassen, die abstrakte Baupläne beschreiben (nicht zu verwechseln mit "abstrakten Klassen" - einem Begriff, der unglücklicherweise mit anderweitiger Semantik belegt ist), ist ein Exemplar immer konkret. Von jeder Klasse kann ich beliebig viele Exemplare erzeugen. Ein Exemplar ist einer Klasse zugehörig, und hat darüber hinaus eine (abprüfbare) Identität, die es auf diese Weise zu einem identifizierbaren, konkreten Objekt macht. Ich hoffe der Unterschied ist verständlich dargestellt. Ich bitte darum, mir nachzusehen, dass ich das Exemplar am Ende der Klassenhierarchie so nicht stehen lassen konnte.
Julian Fietkau
|
Zitat |
Registriert seit: 14. Aug 2005 1.859 Beiträge Delphi 11 Alexandria |
#7
Hallo zusammen,
ich will mich erst mal bedanken, für die viele Arbeit die Ihr Euch gemacht habt. Ich werde mal versuchen die von Euch angeben Tipps umzusetzen. Dafür werde ich die 2 Modelle, die mir so vorschweben mal getrennt umzusetzen (im kleineren Maßstab). Wenn ich soweit bin, werde ich sie hier mal zur Diskussion vorstellen. Bis bald Chemiker
wer gesund ist hat 1000 wünsche wer krank ist nur einen.
|
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |