Discussion:
Klassenmodule vs. keine Klassenmodule (in meinem Fall)
(zu alt für eine Antwort)
Bodo Greiner
2005-12-01 11:18:01 UTC
Permalink
Hallo,

bei (schon früher erwähnter) leicht chaotischer Anwendung, die ich
übernommen habe, sieht's danach aus, als ob bei diversen Formularen alles
Mögliche neu programmiert werden müßte, weil es langsam läuft und
Fehlermeldungen en masse gibt. Beispiel: Bereits in einer Form_Load Prozedur
eines Formulars, in dem Bestellungen bearbeitet werden, werden alle
möglichen Werte in zugrundeliegende Tabellen (die nicht verknüpft sind :-))
reingeschrieben und obendrein im Modul dieses Formulars als modulweit
deklarierte Variablen gespeichert. Für den Fall, daß die Bestellung
abgebrochen wird, werden die bereits eingetragenen Werte aus den Tabellen
wieder rausgelöscht.

Es würde mehr Sinn machen, alles erst dann in die Tabellen reinzuschreiben,
wenn definitiv eine Bestellung vom Formular aus aufgegeben wird. Dadurch,
daß aber erst in Tabellen reingeschrieben und dann - bei Abbruch der
Bestellung - wieder rausgelöscht wird, gibt es so ca. 1,5 Meter Code im
Formularmodul, und das Ganze läuft entsprechend "superschnell" ;-)

Meine Frage: Wenn ich das also neu programmiere, sollte ich es dann
(relativ) objektorientiert tun mit Klassenmodulen? Einige Grundlagen von
Klassenmodulen und Vorzüge davon kenne ich; allerdings weiß ich nicht, wie's
aussieht mit dem Aufwand für diverse Berechnungen, die dann auch
programmiert werden müssen auf diese (relativ) objektorientierte Weise.

Spart man dabei Arbeit? Oder fällt man auf die Schnauze, wenn man sich nicht
"perfekt" mit dieser Technik auskennt? Das Thema Klassen wird in Lehrbüchern
zu Äccess allgemein stiefmütterlich behandelt (Ausnahme: "Das Access 2003
Entwicklerbuch" von André Minhorst, durch das ich überhaupt auf die Idee
komme mir zu überlegen, ob ich mit Klassen arbeiten will).

Woher (Bücher? Kollegen? Internet? MSDN?) bekommen denn Access-Programmierer
ihr /detailliertes/ Know-how zu Klassenmodulen?

Gruß, Bodo
Michael Zimmermann
2005-12-01 11:44:02 UTC
Permalink
Hallo!
Post by Bodo Greiner
bei (schon früher erwähnter) leicht chaotischer
Anwendung, die ich übernommen habe, sieht's danach aus,
als ob bei diversen Formularen alles Mögliche neu
programmiert werden müßte, weil es langsam läuft und
Fehlermeldungen en masse gibt. Beispiel: Bereits in einer
Form_Load Prozedur eines Formulars, in dem Bestellungen
bearbeitet werden, werden alle möglichen Werte in
zugrundeliegende Tabellen (die nicht verknüpft sind :-))
reingeschrieben und obendrein im Modul dieses Formulars
als modulweit deklarierte Variablen gespeichert. Für den
Fall, daß die Bestellung abgebrochen wird, werden die
bereits eingetragenen Werte aus den Tabellen wieder
rausgelöscht.
"Entwicklerhandschrift." ;-)
Post by Bodo Greiner
Es würde mehr Sinn machen, alles erst dann in die
Tabellen reinzuschreiben, wenn definitiv eine Bestellung
vom Formular aus aufgegeben wird. Dadurch, daß aber erst
in Tabellen reingeschrieben und dann - bei Abbruch der
Bestellung - wieder rausgelöscht wird, gibt es so ca. 1,5
Meter Code im Formularmodul, und das Ganze läuft
entsprechend "superschnell" ;-)
Meine Frage: Wenn ich das also neu programmiere, sollte
ich es dann (relativ) objektorientiert tun mit
Klassenmodulen? Einige Grundlagen von Klassenmodulen und
Vorzüge davon kenne ich; allerdings weiß ich nicht, wie's
aussieht mit dem Aufwand für diverse Berechnungen, die
dann auch programmiert werden müssen auf diese (relativ)
objektorientierte Weise.
Spart man dabei Arbeit?
Nur wenn Du den Code immer wieder verwendest.

Meine persönliche /Meinung/:

Eine Funktion, die in einer großen Schleife Werte addiert,
sollte man nicht in eine Klasse einpacken, schon gar, wenn
diese Funktion nur einmal gebraucht wird. Durch die
Wrapper-Klasse wird's nur unnötig verlangsamt.

Funktionalitäten, die man anschaulich als Objekt sehen kann,
z. B. ein File-Dialog, eine Textdatei, einen Ordner, eine
Hierarchie, und die man immer wieder benutzt, sind in einer
Klasse besser aufgehoben.

Ich selbst benutze aus prinzipiellen Erwägungen nur
generische Klassen, die sich auf Objekte der Datenbank-
Meta-Ebene beziehen, nie Klassen für konkrete Inhalte.

Also z. B. keine "Kundenklasse" o. ä. Die (sinnvolle)
generische Klasse, die das gleichartige Behandeln
beliebiger Datenzusammenstellungen erlaubt, gibt es
schon, die heißt Recordset.

Aber z. B. eine Stack- und eine Queue-Klasse, weil das
allgemeine Objekte sind, die man immer und überall braucht.
Post by Bodo Greiner
Oder fällt man auf die Schnauze,
wenn man sich nicht "perfekt" mit dieser Technik
auskennt?
Naa. Falls Du nicht gerade in komplexen Objektmodellen
Zirkelbezüge fabrizierst, ist Klassenprogrammierung
recht robust und nicht sonderlich schwierig.
Post by Bodo Greiner
Das Thema Klassen wird in Lehrbüchern zu Äccess
allgemein stiefmütterlich behandelt
Generell solltest Du Dir von Klassen keine Wunderdinge
erwarten. Du kannst damit dasselbe machen wie in
Standardprozeduren, nur daß die wiederholte Verwendung
weitaus anschaulicher ist.

Gruß aus Mainz
Michael
Bodo Greiner
2005-12-01 11:57:37 UTC
Permalink
Hallo Michael,

ganz herzlichen Dank für Deine superschnelle Antwort!
Post by Michael Zimmermann
Eine Funktion, die in einer großen Schleife Werte addiert,
sollte man nicht in eine Klasse einpacken, schon gar, wenn
diese Funktion nur einmal gebraucht wird. Durch die Wrapper-Klasse wird's
nur unnötig verlangsamt.
Funktionalitäten, die man anschaulich als Objekt sehen kann,
z. B. ein File-Dialog, eine Textdatei, einen Ordner, eine
Hierarchie, und die man immer wieder benutzt, sind in einer
Klasse besser aufgehoben.
Ich selbst benutze aus prinzipiellen Erwägungen nur
generische Klassen, die sich auf Objekte der Datenbank-
Meta-Ebene beziehen, nie Klassen für konkrete Inhalte.
Post by Bodo Greiner
Das Thema Klassen wird in Lehrbüchern zu Äccess
allgemein stiefmütterlich behandelt
Generell solltest Du Dir von Klassen keine Wunderdinge
erwarten. Du kannst damit dasselbe machen wie in
Standardprozeduren, nur daß die wiederholte Verwendung
weitaus anschaulicher ist.
Da geht's schon los: Woher hast Du beispielsweise erfahren, was eine
generische Klasse, eine Stack- und eine Queue-Klasse sind? Aus einem Buch?
Aus einer anderen Programmiersprache? Ich höre diese Dinge zum ersten Mal,
obwohl ich fast alle deutschsprachigen Programmierbücher zu Hause habe...

Gruß, Bodo
Michael Zimmermann
2005-12-01 12:56:49 UTC
Permalink
Hallo!
Post by Bodo Greiner
Da geht's schon los: Woher hast Du beispielsweise
erfahren, was eine generische Klasse, eine Stack- und
eine Queue-Klasse sind? Aus einem Buch?
Weiß nicht mehr. Großenteils stammen solche Begriffe aus dem
Studium. /Muß/ man zum Programmieren nicht haben, /kann/
aber helfen. ;-)

Generisch: Allgemein, eine Spezialisierung erfolgt durch
Parameter.

Ein Stack ist ein Stapelspeicher, also eine Struktur, die
den zuletzt abgelegten Wert beim Lesen wieder ausgibt und
dessen Vorgänger dann an die Ausgabestelle setzt. (First
in, last out.)

Ein Queue macht das gleiche, aber wie eine
Warteschalnge. (First in, first out.)

Statt den nötigen Code direkt in eine Prozedur zu schreiben
oder eine Funktion aufzurufen, finde ich es halt ganz
anschaulich, zu schreiben:

Set s1 = New Stack

s1.Push Wert
Debug.print s1.Pop
...

Set s1 = Nothing

und wenn Du zwei brauchst, machst Du einfach noch ein

Set s2 = New Stack

Für meinen Geschmack einige ganz gute Kapitel zum Thema
Klassen findest Du in Michael Kofler: Visual Basic 6

Ansonsten mußt Du einfach nur mit dem Begriff 'Klasse' im
Betreff hier fragen. Wenn Paul Rohorzka oder Gottfried
Lesigang Dich bemerken, tätowieren sie Dir den
Klassenquellcode, wohin Du ihn haben willst. ;-)

Gruß aus Mainz
Michael
Bodo Greiner
2005-12-01 14:16:41 UTC
Permalink
Hallo Michael,

danke für die Erklärungen!
Post by Michael Zimmermann
Für meinen Geschmack einige ganz gute Kapitel zum Thema
Klassen findest Du in Michael Kofler: Visual Basic 6
Dieses Buch habe ich tatsächlich als PDF - vor ca. 3 Jahren in weiser
Voraussicht beschafft???
Post by Michael Zimmermann
Ansonsten mußt Du einfach nur mit dem Begriff 'Klasse' im
Betreff hier fragen. Wenn Paul Rohorzka oder Gottfried
Lesigang Dich bemerken, tätowieren sie Dir den
Klassenquellcode, wohin Du ihn haben willst. ;-)
Gut zu wissen! Hauptsache, ich kann den Code lesen... Hinterteil wäre daher
etwas weniger gut.

Gruß, Bodo
Gottfried Lesigang
2005-12-02 19:42:45 UTC
Permalink
Grüß euch!
Post by Michael Zimmermann
Ansonsten mußt Du einfach nur mit dem Begriff 'Klasse' im
Betreff hier fragen. Wenn Paul Rohorzka oder Gottfried
Lesigang Dich bemerken, tätowieren sie Dir den
Klassenquellcode, wohin Du ihn haben willst. ;-)
Ich wurde gerufen! Die Nadeln sind ausgeglüht, es kann losgehen! Wo ist der
Delinquent?

Also: /Meine/ persönliche Meinung: Ohne Klassen könnte ich mir das
Programmieren gar nicht mehr vorstellen. Alles "ohne" hat einen sehr langen
Bart ;-)

Auch wenn Michael meint, dass man für Klassenprogrammierung nicht allzu viel
KnowHow braucht, ganz so trivial ist es dann auch wieder nicht. Klar, das
Anlegen einer Klasse und deren Instanzierung hat man schnell gelernt. Aber
es kommt ja nicht darauf an, eine Funktion, die bisher gut in einem
allgemeines Modul aufgehoben war, in eine Klasse zu packen. Das macht nur
den Aufruf mühsamer...

In allgemeine Module kommen bei mir eigentlich nur Dinge, wo man sich
eigentlich wundert, dass sie nicht zum Repertoir von VB dazugehören. In
allgemeine Module packe ich noch gerne Konstanten, Error-Codes, Enums...

Klassen verwende ich dort, wo ich viele gleich strukturierte, inhaltlich
aber unterschiedliche Dinge darstellen will. Also dann, wenn ich von
vornherein absehen kann, dass ich mehrere Instanzen haben werde wollen
(können).

Oder für Bereiche mit ganz klar abgekapselter Funktionalität, wie z.B. ein
FileSystem-Objekt (wie von Michael vorgeschlagen). Gerade dieses finde ich
allerdings kein so gutes Beispiel, es sei denn es ist eine Art
Collection-Klasse, in der dann jede gefundene Datei wieder als eigenes
Objekt "drin" ist. Wirklich toll läuft es nämlich erst, wenn man zu jeder
Klasse (wo das sinnvoll ist) auch eine typenstrenge Listenklasse anlegt -
mit "For Each" und allem "Drum und Dran".

Ich verstehe euch Klassenfeinde ;-) echt nicht. Jeder nutzt Klassen
exzessiv, denn jedes Form, Control etc. ist ein Objekt. Jeder erlebt den
grandios intuitiven und einfachen Zugang! Wie man sich mittels Punkt-Syntax
durch die Objekte "durchhanteln" kann ist doch einfach *klasse* ;-)

Ich erweitere z.B. gerne vorhandene Objekte um weitere Möglichkeiten. z.B.
habe ich eine Listbox-Wrapper-Klasse, die die Column-Eigenschaft auch zum
Schreiben anbietet. Außerdem hat diese Klasse eine "SwapLines"-Methode, eine
ApplyColumnHeads-Methode, direkte Zugriffs-Properties für die
Überschriften - und sie "verzählt" sich nicht beim ListIndex, wenn man
ColumnHeads verwendet usw..

Oder eine Form-Behaviour-Klasse. Damit konnte ich in einem Projekt an die 30
Formulare mit allgemeinen Verhalten ausstatten. Im Form-Modul genügt dann
ein einziger Init-Aufruf in Form_Open. Die Pflege ist so natürlich auch viel
einfacher!

Ich finde es beeindruckend, dass ich weitgehend intuitiv z.B. Excel
"fernsteuern" kann. Das wäre ohne Objekte und deren Eigenschaften und
Methoden doch unmöglich. Außerdem ist Windows "Event-driven" - und ohne
Klassen verzichte ich auf dieses starke Steuerungsinstrument

Zu jeder Db-Tabelle mache ich mir (z.T. mit selbstgestricktem Generator)
eine Element- und eine Listenklasse. Michael würde jetzt einwenden, dass man
ja alles auch über SQL lösen kann. Da wende ich halt ein, dass man natürlich
auch alles mit GoTo oder in Assembler lösen kann ;-)
Die so entstandenen Element- und Listenklassen erweitere ich dann um
spezifische Funktionen, die ich immer wieder brauche:

<Seminarverwaltung>
"EinSeminar.MeineTeilnehmer.AnzahlFrauen"
finde ich einfach lesbarer als einen SQL-String (der natürlich "im Inneren"
verwendet wird!)

<Gastgewerbe>
"EineBar.MeinLokal.MeineBetreiberGesellschaft.MeinGF.PrettyName" liefert
z.B. ausgehend von einer Bar über dessen Lokal, über dessen Betreiber den
bereits formattierten Namen des Geschäftsführers. Klar geht das auch mittels
SQL-Ungetüm...

Also: Eine Lanze für die Klassen! Außerdem bin ich Brotberuf Lehrer, habe
also auch dort ständig mit Klassen zu tun ;-)

Aber: (@Bodo) Du hast deutlich ausgedrückt, dass du zwar viele Bücher hast,
aber mit der OOP-Programmierung (ich unterstelle: mit der Programmierung)
noch nicht so routiniert bist. Dafür nimmst du IMO den Mund gegen die
vorigen Programmierer etwas zu voll (auch wenn da einiges wohl wirklich
sub-optimal gelöst wurde...) Ein vorhandenes Projekt konsequent auf OOP
umzubauen heißt es völlig neu zu machen. Wenn das für dich Neuland ist, dann
stell dich auf viele leere Kilometer ein...

lg
Gottfried
Michael Zimmermann
2005-12-02 21:10:26 UTC
Permalink
Hallo!
Post by Gottfried Lesigang
Post by Michael Zimmermann
Ansonsten mußt Du einfach nur mit dem Begriff 'Klasse'
im Betreff hier fragen. Wenn Paul Rohorzka oder
Gottfried Lesigang Dich bemerken, tätowieren sie Dir den
Klassenquellcode, wohin Du ihn haben willst. ;-)
Ich wurde gerufen! Die Nadeln sind ausgeglüht, es kann
losgehen! Wo ist der Delinquent?
Also: /Meine/ persönliche Meinung: Ohne Klassen könnte
ich mir das Programmieren gar nicht mehr vorstellen.
Alles "ohne" hat einen sehr langen Bart ;-)
Die mit den längsten Bärten sind die klügsten Druiden. ;-)
Post by Gottfried Lesigang
Ich finde es beeindruckend, dass ich weitgehend intuitiv
z.B. Excel "fernsteuern" kann. Das wäre ohne Objekte und
deren Eigenschaften und Methoden doch unmöglich. Außerdem
ist Windows "Event-driven" - und ohne Klassen verzichte
ich auf dieses starke Steuerungsinstrument ...
Zu jeder Db-Tabelle mache ich mir (z.T. mit
selbstgestricktem Generator) eine Element- und eine
Listenklasse. Michael würde jetzt einwenden, dass man ja
alles auch über SQL lösen kann.
Da habe ich in der Tat einiges einzuwenden, nicht nur daß
es auch über SQL ginge. Das ist m. E. genau die falsche
Art, mit Klassen umzugehen.

1.) SQL ist keine Geschmackssache. Zur relationalen Theorie
gehört auch eine vollständige relationale Sprache. Das ist
SQL. Jede von einem Einzelkämpfer gebasteltete Ersatzlösung
wird dem, was sich internationale Gremien kluger Köpfe
ausgedacht haben, im Zweifel unterlegen sein. Zumindest
ist ein allgemeingültiger Beweis vorzulegen, daß die
Sprache die gesamte relationale Funktionalität abdeckt.

2.) Zu Klassen gehört mehr als nur ein paar Module mit
Code. Zu Klassen gehört zunächst die mathematische
Klassentheorie. Eine Klasse ist die extensionale
Betrachtungsweise eines einwertigen Prädikats, also
in etwa dasselbe wie eine Menge. Deshalb ist es ein
logischer Fehler, Individuen als Klassen zu konzipieren.
Die Individuen sind Instanzen der Klasse. Das habe ich
dadurch angedeutet, wenn ich sagte, Klassen müßten
generisch sein. Tauglich ist eine Klasse dann, wenn
sie allen Theoremen der Klassenlogik entspricht.

3.) Durch dieses Vorgehen wird die Datenbankstruktur
zweimal modelliert. Alle Änderungen müssen daher auch
zweimal vollzogen werden. Das eröffnet die Möglichkeit
zu Widersprüchen. Redundanz ist nicht nur in den Nutzdaten
von Übel.
Post by Gottfried Lesigang
Da wende ich halt ein, dass man natürlich auch alles mit
GoTo oder in Assembler lösen kann ;-)
Ja, klar. Spricht ja auch nichts gegen GoTo und Assembler.
Post by Gottfried Lesigang
Die so entstandenen Element- und Listenklassen erweitere
ich dann um spezifische Funktionen, die ich immer wieder
<Seminarverwaltung>
"EinSeminar.MeineTeilnehmer.AnzahlFrauen"
finde ich einfach lesbarer als einen SQL-String (der
natürlich "im Inneren" verwendet wird!)
Ich wußte nicht, daß es inzwischen schon soo schlimm um
Dich steht. ;-)

Eine Klasse für Tabellenzugriff sollte auf weitaus höherer
Abstraktionsebene ansetzen, so daß sie für jede Tupelmenge
verwendbar ist. Diese unverzichtbare Klasse gibt es schon:
das Recordset.

Deine Beispiele laufen darauf hinaus, daß es in Excel
z. B. eine Blatt1-Klasse, eine Blatt2-Klasse, ... und
warum dann nicht auch gleich noch eine SpalteA-Klasse,
eine SpalteB-Klasse, ..., usw. gäbe.

Stattdessen gibt es sinnvollerweise nur eine allgemeine
WorkSheet-Klasse und eine allgemeine Range-Klasse, die
über Parameter auf die aktuell erforderliche Situation
zugespitzt werden.

/So/ wird ein Schuh draus. An der Klassenhierarchie von
Excel kann man sich ein Beispiel nehmen. Die ist in weiten
Teilen hervorragend hierarchisch durchkonzipiert.

Laßt Wein und Brezeln bringen! Grundsatzdiskussion, ick hör
Dir trappsen! ;-)

Gruß aus Mainz
Michael
Gottfried Lesigang
2005-12-02 23:37:35 UTC
Permalink
Grüß dich Michael und alle anderen!
Post by Michael Zimmermann
Die mit den längsten Bärten sind die klügsten Druiden. ;-)
Michael, ich bin enttäuscht! Ich dachte gerade von dir, dass du alles
mathematisch sauber abgeleitet machst. Und jetzt das! Magie, Mystik,
Esoterik - da tun sich ja Abgründe auf...
Post by Michael Zimmermann
[Gottfried über Excel]
Da habe ich in der Tat einiges einzuwenden, nicht nur daß
es auch über SQL ginge. Das ist m. E. genau die falsche
Art, mit Klassen umzugehen.
IMO ist gerade eine Objekt.Hierarchie perfekt dazu geeignet relationale
Zusammenhänge abzubilden! Hast du schon mal den DataSet-Generator von VS.NET
begutachtet? Der legt vollautomatisch genau das an, wovon ich rede. Das
haben auch keine Hohlköpfe gemacht...

Im Buch über ADO.NET beschreib M. Westphal sehr ausführlich die
Schwierigkeiten und Vorteile der Abbildung relationaler Strukturen in
OOP-Hierarchien. Hauptunterschied ist die Verweisrichtung. In Relationalen
Strukturen verweisen die Kinder durch Fremdschlüssel auf die Eltern. in OOP
kennen die Eltern ihre Kinder (und die oft - zusätzlich per
Rückwärtsreferenz - den Parent) - was intuitiver und weniger fehleranfällig
ist (Stichwort RI- aber das hatten wir ja gerade...)
Post by Michael Zimmermann
1.) SQL ist keine Geschmackssache. Zur relationalen Theorie
gehört auch eine vollständige relationale Sprache. Das ist
SQL.
Irgendwie reitest du da zu sehr auf SQL herum. OOP hat ja gar nicht den
Anspruch SQL zu ersetzen. Ganz im Gegenteil kommt im direkten Datenzugriff
(meist in einer eigenen "Datenzugriffsschicht") auch beim OOP'ler natürlich
SQL zum Einsatz.
Post by Michael Zimmermann
Jede von einem Einzelkämpfer gebasteltete Ersatzlösung
wird dem, was sich internationale Gremien kluger Köpfe
ausgedacht haben, im Zweifel unterlegen sein. Zumindest
ist ein allgemeingültiger Beweis vorzulegen, daß die
Sprache die gesamte relationale Funktionalität abdeckt.
Versteh ich nicht! OOP ist doch keine relationale Sprache und hat auch gar
nicht den Anspruch (s. oben!)...
Post by Michael Zimmermann
2.) Zu Klassen gehört mehr als nur ein paar Module mit
Code. Zu Klassen gehört zunächst die mathematische
Klassentheorie. Eine Klasse ist die extensionale
Betrachtungsweise eines einwertigen Prädikats, also
in etwa dasselbe wie eine Menge. Deshalb ist es ein
logischer Fehler, Individuen als Klassen zu konzipieren.
Wir widersprechen uns doch gar nicht! Ganz im Gegenteil! Ich sagte doch,
dass ich Klassen vor allem dort sehe, wo ich schon im Voraus erkenne, dass
ich wahrscheinlich mehrere Instanzen brauchen werde. Deshalb fand ich ja
dein Beispiel vom FileSystem-Objekt nicht ganz glücklich...
Post by Michael Zimmermann
Die Individuen sind Instanzen der Klasse.
Wenn ich also eine Personen-Tabelle habe, kann ich doch eine Personen-Klasse
anlegen, die geeignet ist, mit jeder Instanz genau eine Zeile dieser Tabelle
zu repräsentieren. Der Vorteil dieser Herangehensweise liegt eben darin,
dass ich diese Klasse um weitere Eigenschaften und Methoden erweitern und
auch mit Ereignissen ausstatten kann. Eigenschaften können - wiederum als
Objekt - Inhalte zurückgeben, für dich in SQL einen Join machen muss.
Post by Michael Zimmermann
3.) Durch dieses Vorgehen wird die Datenbankstruktur
zweimal modelliert. Alle Änderungen müssen daher auch
zweimal vollzogen werden.
Ich habe etwas Wichtiges nicht erwähnt: Ich verwende i.A. diese Klassen nur
lesend... Das Problem der Redundanz ist sehr heikel - da geb ich dir recht!
Post by Michael Zimmermann
Da wende ich halt ein, dass man natürlich auch alles mit
GoTo oder in Assembler lösen kann ;-)
Ja, klar. Spricht ja auch nichts gegen GoTo und Assembler.
Das letzte Argument aller veralteten Programmierer: Aber meiner ist
schneller! ;-)
Post by Michael Zimmermann
Die so entstandenen Element- und Listenklassen erweitere
ich dann um spezifische Funktionen, die ich immer wieder
<Seminarverwaltung>
"EinSeminar.MeineTeilnehmer.AnzahlFrauen"
finde ich einfach lesbarer als einen SQL-String (der
natürlich "im Inneren" verwendet wird!)
Ich wußte nicht, daß es inzwischen schon soo schlimm um
Dich steht. ;-)
Eine Klasse für Tabellenzugriff sollte auf weitaus höherer
Abstraktionsebene ansetzen, so daß sie für jede Tupelmenge
das Recordset.
Mir scheint fast, dass du denn Sinn von OOP nicht sehen *willst*. Ich will
ja gerade *nicht* die abstrakte und für jede Tupelmenge verwendbare
Meta-Klasse (denn die gibt es ja schon), sondern einen genau auf diese
Tabelle typenstreng zugeschnittenen Repräsentanten. Diese Klasse kann ich
dann beliebig erweitern. Das ist jedenfalls genau das Konzept in .NET!
Post by Michael Zimmermann
Deine Beispiele laufen darauf hinaus, daß es in Excel
z. B. eine Blatt1-Klasse, eine Blatt2-Klasse, ... und
warum dann nicht auch gleich noch eine SpalteA-Klasse,
eine SpalteB-Klasse, ..., usw. gäbe.
Das finde ich fast schon boshaft ;-) Willst du mir unterstellen, dass ich zu
einer Personentabelle eine "Peter-Klasse", eine "Fritz-Klasse" und eine
"Robert-Klasse" anlegen würde?! Nun gut. Der Michael wäre vielleicht
wirklich eine Klasse für sich ;-)
Post by Michael Zimmermann
Laßt Wein und Brezeln bringen! Grundsatzdiskussion, ick hör
Dir trappsen! ;-)
LOL!

lg
Gottfried
Michael Zimmermann
2005-12-03 17:01:56 UTC
Permalink
Hallo!
Post by Gottfried Lesigang
Grüß dich Michael und alle anderen!
Post by Michael Zimmermann
Die mit den längsten Bärten sind die klügsten Druiden.
;-)
Michael, ich bin enttäuscht! Ich dachte gerade von dir,
dass du alles mathematisch sauber abgeleitet machst. Und
jetzt das! Magie, Mystik, Esoterik - da tun sich ja
Abgründe auf...
Einer meiner Mathe-Professoren (der Klügste, denn er hatte
die längste Zeit um zu lernen gehabt) hatte einen Bart wie
der Weihnachtsmann. ;-)
Post by Gottfried Lesigang
Wir widersprechen uns doch gar nicht! Ganz im Gegenteil!
Ah! ;-)
Post by Gottfried Lesigang
Ich sagte doch, dass ich Klassen vor allem dort sehe, wo
ich schon im Voraus erkenne, dass ich wahrscheinlich
mehrere Instanzen brauchen werde. Deshalb fand ich ja
dein Beispiel vom FileSystem-Objekt nicht ganz
glücklich...
(Text-) Datei war mein Beispiel. Zumindest auf meinem
Rechner gibt es durchaus mehrere Dateien. ;-)
Post by Gottfried Lesigang
Post by Michael Zimmermann
3.) Durch dieses Vorgehen wird die Datenbankstruktur
zweimal modelliert. Alle Änderungen müssen daher auch
zweimal vollzogen werden.
Ich habe etwas Wichtiges nicht erwähnt: Ich verwende i.A.
diese Klassen nur lesend... Das Problem der Redundanz ist
sehr heikel - da geb ich dir recht!
Insbesondere vor dem Hintergrund, daß Klassen eigentlich
in erster Linie Code-Redundanz vermeiden sollen. Daher ja
auch das Vererbungskonzept.

Diese Vermeidung setzt aber einen hohen Abstraktionsgrad
voraus.
Post by Gottfried Lesigang
Mir scheint fast, dass du denn Sinn von OOP nicht sehen
*willst*. Ich will ja gerade *nicht* die abstrakte und
für jede Tupelmenge verwendbare Meta-Klasse (denn die
gibt es ja schon), sondern einen genau auf diese Tabelle
typenstreng zugeschnittenen Repräsentanten.
Ein sinnvolles Datenbank-Objekt ist in meinen Augen eines,
das in /jeder/ Datenbank vorkommen könnte.

Eine Netz-Klasse, die m:n-Referenzen darstellt - okay,
eine Hierarchie-Klasse, die 1:n-Referenzen darstellt - okay,
selbst wenn es in einer DB mal zufällig keine m:n-Beziehung
gebn sollte: es /könnte/ sie aber geben, aber eine
Kundenklasse, obwohl es in vielen DBen gar keine Kunden
gibt und nicht geben kann, halte ich für überflüssige
Arbeit. Dann lieber eine Klasse wie das Recordset, das
entsprechend parametrisiert für /jede/ Tabelle stehen
kann. Auch irgendwelche DataAdapter-Klassen und ähnliche,
die für /Datenbanken an sich/ verwendbar sind, machen Sinn.

Der Grundgedanke, der von je her hinter OOP stand, war
die multiple Verwendbarkeit von Code, um das Ideal eine
Änderung - ein Platz zu erreichen.

Ohne Dich damit jetzt zwangsbeglücken zu wollen: Siehst Du
aber, worum es mir geht?

Gruß aus Mainz
Michael
Gottfried Lesigang
2005-12-03 18:55:41 UTC
Permalink
Hallo zurück!
Post by Michael Zimmermann
Post by Gottfried Lesigang
Wir widersprechen uns doch gar nicht! Ganz im Gegenteil!
Ah! ;-)
Da höre ich sowas wie einen triumphierenden Unterton!? Mitnichten! Immerhin
bin ich der, der drauf gekommen ist ;-)
Post by Michael Zimmermann
Insbesondere vor dem Hintergrund, daß Klassen eigentlich
in erster Linie Code-Redundanz vermeiden sollen. Daher ja
auch das Vererbungskonzept.
Das VB(A) ja leider nicht unterstützt!
Post by Michael Zimmermann
Post by Gottfried Lesigang
Mir scheint fast, dass du denn Sinn von OOP nicht sehen
*willst*. Ich will ja gerade *nicht* die abstrakte und
für jede Tupelmenge verwendbare Meta-Klasse (denn die
gibt es ja schon), sondern einen genau auf diese Tabelle
typenstreng zugeschnittenen Repräsentanten.
Ein sinnvolles Datenbank-Objekt ist in meinen Augen eines,
das in /jeder/ Datenbank vorkommen könnte.
Eine Netz-Klasse, die m:n-Referenzen darstellt - okay,
eine Hierarchie-Klasse, die 1:n-Referenzen darstellt - okay,
selbst wenn es in einer DB mal zufällig keine m:n-Beziehung
gebn sollte: es /könnte/ sie aber geben, aber eine Kundenklasse, obwohl es
in vielen DBen gar keine Kunden
gibt und nicht geben kann, halte ich für überflüssige
Arbeit. Dann lieber eine Klasse wie das Recordset, das
entsprechend parametrisiert für /jede/ Tabelle stehen
kann. Auch irgendwelche DataAdapter-Klassen und ähnliche,
die für /Datenbanken an sich/ verwendbar sind, machen Sinn.
Sind denn die Entwickler von ADO.NET und dem DataSet-Generator allesamt
Hohlköpfe?
Genau die von mir beschriebene Vorgehensweise wird in .NET als *der* Weg der
DB-Programmierung verfolgt. Deine Sicht unterschreibe ich für das Data-Tier
einer 3-Schicht-Applikation. Im Business-Tier will ich mich - solide
Umsetzung vorausgesetzt! - aber um die Details der DB überhaupt nicht mehr
kümmern müssen! Dort will ich typenstrenge Objekte, die Standard-Aufgaben
bereits fix-fertig anbieten.
Post by Michael Zimmermann
Der Grundgedanke, der von je her hinter OOP stand, war
die multiple Verwendbarkeit von Code, um das Ideal eine
Änderung - ein Platz zu erreichen.
Seit es Programmierer gibt - Denn die sind alle faule Hunde! - ist *genau
das* der Grundgedanke (fast) jeder Neuerung: Sprungbefehle, Schleifen,
Prozeduren etc. haben doch alle *genau diesen* Zweck! OOP geht da mit der
Instanzierbarkeit und der Kapselung doch viel weiter! Stell die vor, du
müsstest alle Zustände aller Controls eines gut gefüllten Formulars in
umfangreichen Arrays irgendwie puffern - ein Graus! Paul hat schon einiges
zur "Sichtbarkeit" (Und da geht es nicht nur um Intellisense!) und zu den
Vorgabewerten gesagt. Würdest du wirklich lieber nur eine *allgemeine*
Control-Klasse haben? Wozu so konkrete Dinge wie Textboxen, Labels etc.?

Bin ich froh, dass die von dir doch sonst durchaus gelobten
Access-Entwickler nicht "aus prinzipiellen Erwägungen" auf Objekte
verzichtet haben!

Außerdem hat Paul deutlich gemacht, wie schwer wartbar verteilte
SQL-Statements sind, wenn z.B. ein Feldname geändert werden muss...
Post by Michael Zimmermann
Ohne Dich damit jetzt zwangsbeglücken zu wollen: Siehst Du
aber, worum es mir geht?
Ich sehe worum es dir geht. Du willst weiter in dem Gefühl der Unfehlbarkeit
leben ;-)

Michael, wenn es um die Struktur einer relationalen DB geht, kann dir kaum
einer das Wasser reichen! Aber von OOP hast du glaube ich - mangels
Erfahrung - nicht gar so viel Ahnung. Du benutzt zwar sicher Objekte wie
Controls und Recordsets, argumentierst aber trotzdem dagegen...

Ich weiß nicht wie viele z.B. wissen, dass man in einer Klasse z.B. eine
Textbox "WithEvents" deklarieren kann, dieser dann eine Referenz auf eine
konkrete Textbox irgendeines Formulars zuweisen kann um dann *dort* auf die
Ereignisse der Textbox genau so zu reagieren wie im Formular-Modul. Auf
diese Weise z.B. funktioniert meine FormBehaviour-Klasse. In dieser Klasse
ist natürlich auch eine Form-Variable "WithEvents" deklariert. ich kann also
auf Ereignisse wie "Form_BeforeInsert", "Form_BeforeDelete" etc.
einheitlich - weil zentral! - reagieren. Das ist *wirklich* Vermeidung von
Redundanz!

Ich bleibe dabei: Ich finde
"EineBar.MeinLokal.MeineBetreibergesellschaft.MeinGF.PrettyName" einfach
besser als ein SQL-Ungetüm. Deine Meinung teile ich dort, wo es um den
letzten Tick Performance geht. Genau so argumentiert man übrigens immer,
wenn es um veraltete Techniken geht ;-)

Ich liebe eine gepflegte Grundsatzdiskussion!
lg
Gottfried
Michael Zimmermann
2005-12-04 17:54:55 UTC
Permalink
Hallo!
Post by Gottfried Lesigang
Post by Michael Zimmermann
Insbesondere vor dem Hintergrund, daß Klassen eigentlich
in erster Linie Code-Redundanz vermeiden sollen. Daher
ja auch das Vererbungskonzept.
Das VB(A) ja leider nicht unterstützt!
Ja. Leider.
Post by Gottfried Lesigang
Post by Michael Zimmermann
Der Grundgedanke, der von je her hinter OOP stand, war
die multiple Verwendbarkeit von Code, um das Ideal eine
Änderung - ein Platz zu erreichen.
Seit es Programmierer gibt - Denn die sind alle faule
Hunde! - ist *genau das* der Grundgedanke (fast) jeder
Neuerung: Sprungbefehle, Schleifen, Prozeduren etc. haben
doch alle *genau diesen* Zweck! OOP geht da mit der
Instanzierbarkeit und der Kapselung doch viel weiter!
Du mußt mich nicht von den Vorteilen von OOP überzeugen.
Ich benutze seit langem eigene Klasenhierarchien (seit
A 97 um genau zu sein, vorher ging es schlecht). Und da
ich nur Klassen erstelle, die allgemein genug sind, daß
sie in jeder Applikation gleichen Typs verwendbar sind,
komme ich auch in den vollen Genuß ihrer Vorteile.

Aber eine Datenbankklasse, die nicht grundsätzlich in jeder
Datenbank anwendbar ist, ist deplaziert.
Post by Gottfried Lesigang
Stell die vor, du müsstest alle Zustände aller Controls
eines gut gefüllten Formulars in umfangreichen Arrays
irgendwie puffern - ein Graus! Paul hat schon einiges
zur "Sichtbarkeit" (Und da geht es nicht nur um
Intellisense!) und zu den Vorgabewerten gesagt. Würdest
du wirklich lieber nur eine *allgemeine* Control-Klasse
haben? Wozu so konkrete Dinge wie Textboxen, Labels etc.?
Die sind doch nicht konkret?!? Diese Controls gibt es
prinzipiell in jeder Anwendung. Universeller geht's kaum.
Wobei eine Control-Klasse, die die gemeinsamen Eigenschaften
zusammenfaßt und von der die genannten Klassen erben, nicht
nur erforderlich ist, sondern auch existiert.
Post by Gottfried Lesigang
Bin ich froh, dass die von dir doch sonst durchaus
gelobten Access-Entwickler nicht "aus prinzipiellen
Erwägungen" auf Objekte verzichtet haben!
Ich auch. Objekte sind phantastisch, wenn sie generisch
sind.
Post by Gottfried Lesigang
Michael, wenn es um die Struktur einer relationalen DB
geht, kann dir kaum einer das Wasser reichen! Aber von
OOP hast du glaube ich - mangels Erfahrung - nicht gar so
viel Ahnung.
Keine sachlichen Argumente mehr, daß Du die Büchse der
Pandora aufmachst? Na gut, auf einen Schelmen anderthalb.

Ahnungslosigkeit unterstelle ich wiederum Leuten, die
Klassen bis hinunter zur Datenebene bilden. Da fehlen
die theoretischen Grundlagen über die Notwendigkeit
generischer Codierung. Das Vorrecht des Autodidakten.

So verschieden sind die Ansichten ...
Post by Gottfried Lesigang
Du benutzt zwar sicher Objekte wie Controls und
Recordsets, argumentierst aber trotzdem dagegen...
Du mißverstehst mich völlig. Ich plädiere nicht gegen
Objekte. Ich plädiere nur gegen schlechte Objekte, also
solche, die nicht die Anwendungsebene sondern die
Datenebene thematisieren. Daten sind Eigenschaften von
Objekten und nicht selbst Objekte, bzw. falls man es in
.net-Manier treibt, primitive Objekttypen.

Schau Dir die Objekthierarchien der gängigen
Office-Programme an. Sie konkretisieren maximal bis
zu Klassen, die anwendungsuniversell sind, aber nie
bis in individuelle Inhalte hinein. Warum wohl?
Post by Gottfried Lesigang
Ich weiß nicht wie viele z.B. wissen, dass man in einer
Klasse z.B. eine Textbox "WithEvents" deklarieren kann,
dieser dann eine Referenz auf eine konkrete Textbox
irgendeines Formulars zuweisen kann um dann *dort* auf
die Ereignisse der Textbox genau so zu reagieren wie im
Formular-Modul. Auf diese Weise z.B. funktioniert meine
FormBehaviour-Klasse. In dieser Klasse ist natürlich auch
eine Form-Variable "WithEvents" deklariert. ich kann also
auf Ereignisse wie "Form_BeforeInsert",
"Form_BeforeDelete" etc. einheitlich - weil zentral! -
reagieren. Das ist *wirklich* Vermeidung von Redundanz!
Schon okay, das GIBT'S JA AUCH IN JEDER DB. Aber doch keine
KUNDEN. Und selbst wenn, haben sie in verschiedenen DBen
verschiedene Eigenschaften. Bankkunden haben keine Haarfarbe
und Friseurkunden kein Konto.
Post by Gottfried Lesigang
Deine Meinung teile
ich dort, wo es um den letzten Tick Performance geht.
Es geht nicht um Performance. Es geht um den nötigen
Abstraktionsgrad.

Ich benutze z. B. eine Hierarchy-Klasse mit Nodes und
Leaves, um Hierarchien aus Tabellen zu lesen, also eine
Art Tree ohne View.

Ich würde es für keine gute Idee halten, statt einer solchen
allgemeinen Klasse bzw. einer Klassenhierarchie, je eine
Kunden-Bestellungen-Klasse, eine Besitzer-Fahrzeuge-Klasse,
eine Bestellungen-Bestelldetails-Klasse etc. zu haben
und dann bei DBen mit anderen Themen den ganzen Kram wieder
neu schreiben zu müssen, weil es andere Tabellen gibt.

Die generische Klasse funktioniert in /jeder/ DB mit /jeder/
1:n-Kaskade. Das allen Gemeinsame ist modelliert, die
Steurung der Unterschiede (Tabellen-, Feldnamen) erfolgt
über Eigenschaften der Klasse.

Wenn ich in jeder Anwendung, nur weil sie ein anderes Thema
hat, mir neue Klassenhierarchien basteln muß, statt nur die
im Lauf der Jahre zusammengekommenen einfach mit anderen
Parametern zu verwenden, weil sie so abstrahiert sind, daß
sie eigentlich immer passen, dann habe ich den Grundgedanken
von OOP ad absurdum geführt.

Da sich aber die Argumente nur in rauherem Ton wiederholen
zu beginnen scheinen, steige ich an dieser Stelle aus der
sich abzeichnenden Endloschleife aus.

Gruß aus Mainz
Michael
Paul Rohorzka
2005-12-04 20:45:26 UTC
Permalink
Hallo Michael et al!

(Michael Zimmermann:)
Post by Michael Zimmermann
[...]
Aber eine Datenbankklasse, die nicht grundsätzlich in jeder
Datenbank anwendbar ist, ist deplaziert.
Nein, da muss ich dir widersprechen. Ich schreibe keine allgemeinen
Datenbanken, sondern ich schreibe eine spezielle Datenbankanwendung, die
eine konkrete Problemstellung adressiert. Und deshalb möchte ich neben
den vielen generischen Trümmern sehr wohl auch spezialisierte Klassen
verwenden.

(Gottfried Lesigang:)
Post by Michael Zimmermann
Post by Gottfried Lesigang
Stell die vor, du müsstest alle Zustände aller Controls
eines gut gefüllten Formulars in umfangreichen Arrays
irgendwie puffern - ein Graus! Paul hat schon einiges
zur "Sichtbarkeit" (Und da geht es nicht nur um
Intellisense!) und zu den Vorgabewerten gesagt. Würdest
du wirklich lieber nur eine *allgemeine* Control-Klasse
haben? Wozu so konkrete Dinge wie Textboxen, Labels etc.?
(Michael Zimmermann:)
Die sind doch nicht konkret?!? Diese Controls gibt es
prinzipiell in jeder Anwendung. Universeller geht's kaum.
Wobei eine Control-Klasse, die die gemeinsamen Eigenschaften
zusammenfaßt und von der die genannten Klassen erben, nicht
nur erforderlich ist, sondern auch existiert.
Ich denke, hier tut sich auch schon recht schön ein Dilemma auf, das es
festzuhalten gilt: was noch generisch ist, und was schon konkret, ist
nicht zuletzt eine Frage des Blickwinkels.
Für mich allerdings ist die Sache relativ klar: Dinge, die ich
prinzipiell in allen Anwendungen verwenden können können (sic!) wollte,
nenne ich generisch. Andere Dinge, die von der konkreten Problemstellung
/aus Anwendersicht/ abhängen, nenne ich nicht generisch.
Wobei hier die Frage ist, wie viel wir parametrisieren wollen. Denn das
Recordset kann für die Möglichkeit des Datenzugriffs prinzipiell nicht
weniger als eine Kunden-, Bestellungs-, Haustier-, Beleg- oder
Sonstwas-Klasse. Ich muss nur alles entsprechend parametrisieren, zum
Beispiel die Feldnamen. Die Frage ist jetzt, wo diese Parametrisierung
überall stattfinden muss. Im Falle des Recordsets naturgemäß bei jedem
Datenzugriff. Und das ist halt schlimm fehleranfällig.

Neben allen bereits diskutierten Aspekten geht's bei allen im Laufe der
Zeit hinzugekommenen Hilfen und Techniken bei der Software-Entwicklung
IMHO darum, (a) den Aktionsbereich des Entwicklers weg von der Hardware
hin zum eigentlich zu lösenden Problem zu verschieben und damit
verbunden (b) den Entwickler vor sich selbst zu schützen.

Beispiele (unvollständig und nicht streng gereiht):
- Symbolische Assembler statt Maschinencode
- Prozedurale Programmierung statt Spaghetticode (durch Architektur
[Stack] und Befehlssatz der Prozessoren unterstützt)
- "Widmung von Speicher" (Datentypen) statt Byte-Haufen
- Strenge Sprachen/Compiler
- Objektorientierung
- Designer und Code-Generatoren
- ... (was kommt noch?)

(Gottfried Lesigang:)
Post by Michael Zimmermann
Post by Gottfried Lesigang
Bin ich froh, dass die von dir doch sonst durchaus
gelobten Access-Entwickler nicht "aus prinzipiellen
Erwägungen" auf Objekte verzichtet haben!
Ich auch. Objekte sind phantastisch, wenn sie generisch
sind.
Aber warum in aller Welt müssen sie generisch sein?

(Gottfried Lesigang:)
Post by Michael Zimmermann
Post by Gottfried Lesigang
Michael, wenn es um die Struktur einer relationalen DB
geht, kann dir kaum einer das Wasser reichen! Aber von
OOP hast du glaube ich - mangels Erfahrung - nicht gar so
viel Ahnung.
Nun ja, ich denke es ist wohl eher eine dramatisch andere Sicht vom Sinn
von Objektorientierung und vom Softwareentwicklungsprozess im
Allgemeinen. Dass ich diesbezüglich ziemlich bei Gottfried bin, ist
klar, die tendenzielle Untergriffigkeit finde ich aufgrund der wichtigen
wie spannenden Diskussion gerade deshalb schade.
Post by Michael Zimmermann
Ahnungslosigkeit unterstelle ich wiederum Leuten, die
Klassen bis hinunter zur Datenebene bilden. Da fehlen
die theoretischen Grundlagen über die Notwendigkeit
generischer Codierung. Das Vorrecht des Autodidakten.
Auch das hätte nicht sein müssen. Ich überlege gerade, ob ich mich
beleidigt fühlen soll.
Post by Michael Zimmermann
So verschieden sind die Ansichten ...
Also ausnahmsweise keine unumstößlich akademisch/theoretisch stabile
Faktenlage?

(Gottfried Lesigang:)
Post by Michael Zimmermann
Post by Gottfried Lesigang
Du benutzt zwar sicher Objekte wie Controls und
Recordsets, argumentierst aber trotzdem dagegen...
Du mißverstehst mich völlig. Ich plädiere nicht gegen
Objekte. Ich plädiere nur gegen schlechte Objekte, also
solche, die nicht die Anwendungsebene sondern die
Datenebene thematisieren. ...
Aber wer sagt denn, dass Objekte nur für die Anwendungsebene da sind?
Objektorientierung ist ein generisches Konzept, um bei der Nomenklatur
zu bleiben. ;-)
Was ein Objekt ist, und was nicht, ist rein eine Frage der Abstraktion.
Wenn ich wollte, könnte ich jedes Bit in meiner Maschine mit einem
Objekt representieren [bitte keine Belehrung über die Sinnfreiheit
dieses Unterfangens ;-)!].
Post by Michael Zimmermann
... Daten sind Eigenschaften von
Objekten ...
Völlig korrekt.
Post by Michael Zimmermann
... und nicht selbst Objekte, bzw. falls man es in
.net-Manier treibt, primitive Objekttypen.
Warum soll ich nicht das Konzept der Objektorientierung auch auf die
Daten anwenden? Wer sagt, dass ich bei den von der Programmierumgebung
vorgegebenen Datentypen stehen bleiben muss? Ich kann zwei Strings und
ein Integer (und noch ein paar andere Datentypen) zusammenfassen und das
ganze Kunde nennen. Damit habe ich einen weiteren Datentyp definiert.
Post by Michael Zimmermann
Schau Dir die Objekthierarchien der gängigen
Office-Programme an. Sie konkretisieren maximal bis
zu Klassen, die anwendungsuniversell sind, aber nie
bis in individuelle Inhalte hinein. Warum wohl?
Weil die Office-Entwickler meine Problemstellungen nicht kennen konnten!

Auch hier wieder eine Frage des Blickwinkels und Abstraktionsgrades:
<Polemik> Warum gibt es überhaupt für die unterschiedlichen
Office-Anwendungen unterschiedliche Objektmodelle? Warum wird in Word
und Excel einmal ein Document und einmal ein Workbook verwendet, warum
einmal ein Paragraph und einmal ein Worksheet, warum einmal ein
Character und einmal eine Cell, etc? Irgendwie hierarchisch sind die
doch alle aufgebaut!
Die Antwort ist: weil's praktisch und sinnvoll ist!</Polemik>

(Gottfried Lesigang:)
Post by Michael Zimmermann
Post by Gottfried Lesigang
Ich weiß nicht wie viele z.B. wissen, dass man in einer
Klasse z.B. eine Textbox "WithEvents" deklarieren kann,
dieser dann eine Referenz auf eine konkrete Textbox
irgendeines Formulars zuweisen kann um dann *dort* auf
die Ereignisse der Textbox genau so zu reagieren wie im
Formular-Modul. Auf diese Weise z.B. funktioniert meine
FormBehaviour-Klasse. In dieser Klasse ist natürlich auch
eine Form-Variable "WithEvents" deklariert. ich kann also
auf Ereignisse wie "Form_BeforeInsert",
"Form_BeforeDelete" etc. einheitlich - weil zentral! -
reagieren. Das ist *wirklich* Vermeidung von Redundanz!
(Michael Zimmermann:)
Schon okay, das GIBT'S JA AUCH IN JEDER DB. ...
Aber nicht in jeder Anwendung werden sich die Formular völlig gleich
verhalten sollen. Schließlich gibt's ja unterschiedliche Kundenwünsche
und problemspezifische Anforderungen.
Post by Michael Zimmermann
... Aber doch keine
KUNDEN. Und selbst wenn, haben sie in verschiedenen DBen
verschiedene Eigenschaften. Bankkunden haben keine Haarfarbe
und Friseurkunden kein Konto.
Na und? Aber wenn's mir nur in der einen Anwendung das Entwicklerleben
leichter macht und ich dadurch ein paar Fehlerquellen weniger habe, hat
sich's schon rentiert.
Post by Michael Zimmermann
Post by Gottfried Lesigang
Deine Meinung teile
ich dort, wo es um den letzten Tick Performance geht.
Es geht nicht um Performance.
Da sind wir uns ja wohl alle einig.
Post by Michael Zimmermann
Es geht um den nötigen Abstraktionsgrad.
Aber wer soll denn festlegen, was /nötig/ ist? Nötig sind ein Texteditor
und ein Compiler.
Post by Michael Zimmermann
Ich benutze z. B. eine Hierarchy-Klasse mit Nodes und
Leaves, um Hierarchien aus Tabellen zu lesen, also eine
Art Tree ohne View.
Das ist sicher eine gute Sache. Aber warum sollen wir nicht den letzten
Schritt weiter gehen und gleich eine Kunden/Kunde-Objekthierarchie
machen, wo ich dann auch gleich mit schlafwandlerischer Sicherheit
(Namen und Datentypen) Zugriff auf die Attributwerte habe?
Post by Michael Zimmermann
Ich würde es für keine gute Idee halten, statt einer solchen
allgemeinen Klasse bzw. einer Klassenhierarchie, je eine
Kunden-Bestellungen-Klasse, eine Besitzer-Fahrzeuge-Klasse,
eine Bestellungen-Bestelldetails-Klasse etc. zu haben ...
Ja wozu auch? Jede Entität des Datenmodells bekommt zwei Klassen: eine
zur Repräsentation eines Datensatzes (Benennung in der Einzahl) und eine
zur Darstellung einer Datensatzgruppe (Benennung in der Mehrzahl). Die
Bestellungen eines Kunden sind im Objektmodell somit eine weitere
Eigenschaft des Kundenobjekts. Es wird also wohl nie die eine
"Kunden-Bestellungen"-Klasse geben.
Post by Michael Zimmermann
... und dann bei DBen mit anderen Themen den ganzen Kram wieder
neu schreiben zu müssen, weil es andere Tabellen gibt.
Dafür schreiben doch Leute wie Thomas Möller, Gottfried Lesigang,
<tausende mehr hier einfügen>, Paul Rohorzka und nicht zu letzt auch
einige Entwickler bei Microsoft Assistenten und Code-Generatoren!
Post by Michael Zimmermann
Die generische Klasse funktioniert in /jeder/ DB mit /jeder/
1:n-Kaskade. Das allen Gemeinsame ist modelliert, die
Steurung der Unterschiede (Tabellen-, Feldnamen) erfolgt
über Eigenschaften der Klasse.
(Siehe oben meine Bemerkungen zum Thema Parametrisierung und Recordset)
Post by Michael Zimmermann
Wenn ich in jeder Anwendung, nur weil sie ein anderes Thema
hat, mir neue Klassenhierarchien basteln muß, statt nur die
im Lauf der Jahre zusammengekommenen einfach mit anderen
Parametern zu verwenden, weil sie so abstrahiert sind, daß
sie eigentlich immer passen, dann habe ich den Grundgedanken
von OOP ad absurdum geführt.
Aber ich schreibe doch Software nicht um mich asymptotisch dem Zustand
anzunähern, wo ich schon alles einmal programmiert habe, und wo ich nur
mehr alles richtig zusammenfügen muss.
Post by Michael Zimmermann
Da sich aber die Argumente nur in rauherem Ton wiederholen
zu beginnen scheinen, steige ich an dieser Stelle aus der
sich abzeichnenden Endloschleife aus.
Ich würde es schade finden, wenn diese Diskussion - so oft sie auch
schon geführt wurde - nicht auf sachlicher Ebene weitergehen würde.

LG aus Wien,
Paul
--
http://www.softconcept.at - Development, Solutions, Tools
http://access.primary.at - Wiener Access-Stammtisch
Michael Zimmermann
2005-12-05 12:03:24 UTC
Permalink
Hallo!
Post by Paul Rohorzka
Post by Michael Zimmermann
Ich auch. Objekte sind phantastisch, wenn sie generisch
sind.
Aber warum in aller Welt müssen sie generisch sein?
Diese Forderung hat wenig mit Objekt oder nicht Objekt zu
tun. Ich würde auch im rein prozeduralen Bereich erwarten,
daß eine Funktion mindestens zu einem gewissen Grad über
Parameter an verschiedene Anwendungsumgebungen angepaßt
werden kann.

Also z. B. statt eines Function-Stapels
HoleKundeVorname, HoleKundeNachname, HoleLieferantVorname,
HoleLieferantVorname, ... eine einzige:
HoleWert(Entität, Attribut)

Warum ich das prinzipiell für unverzichtbar halte, erfährst
Du am Ende der Geschichte.
Post by Paul Rohorzka
Auch das hätte nicht sein müssen.
Grober Klotz, grober Keil ist bekannt?
Post by Paul Rohorzka
Ich überlege gerade, ob ich mich beleidigt fühlen soll.
Laß es.
Post by Paul Rohorzka
Post by Michael Zimmermann
So verschieden sind die Ansichten ...
Also ausnahmsweise keine unumstößlich
akademisch/theoretisch stabile Faktenlage?
Da bin ich mir nicht sicher. Das herauszufinden, erfodert
eine Meta-Diskussion.
Post by Paul Rohorzka
Dafür schreiben doch Leute wie Thomas Möller, Gottfried
Lesigang, <tausende mehr hier einfügen>, Paul Rohorzka
und nicht zu letzt auch einige Entwickler bei Microsoft
Assistenten und Code-Generatoren!
Meine Meinung zu Assistenten und Code-Generatoren müßtest
Du aber kennen. Das ist nichts, womit man mich irgendwohin
locken kann.
Post by Paul Rohorzka
Post by Michael Zimmermann
Wenn ich in jeder Anwendung, nur weil sie ein anderes
Thema hat, mir neue Klassenhierarchien basteln muß,
statt nur die im Lauf der Jahre zusammengekommenen
einfach mit anderen Parametern zu verwenden, weil sie
so abstrahiert sind, daß sie eigentlich immer passen,
dann habe ich den Grundgedanken von OOP ad absurdum
geführt.
Aber ich schreibe doch Software nicht um mich
asymptotisch dem Zustand anzunähern, wo ich schon alles
einmal programmiert habe, und wo ich nur mehr alles
richtig zusammenfügen muss.
Tatsächlich nicht? Verblüffend! Das ist für mich die einzig
sinnvolle Herangehensweise.

Ich habe es schon zu Schulzeiten im Physik- und
Mathematikunterricht eingebleut bekommen und im
Physik-Studium schon gar:

Wenn Du ein ganz spezielles Problem zu lösen hast, laß
es bleiben.

Stelle erst alle benötigten Formeln zusammen, ermittle dann
mit Größenvariablen die gesuchte Zielgröße und setze erst
/ganz am Schluß/ die aufgabenspezifischen Zahlen (Daten)
Deiner Ausgangsfragestellung in diese allgemeine Lösung
ein.

Schreibe dieselbe in Deine Formelsammlung und habe bei
weiteren gleichartigen Problemen keine unnötige Arbeit
mehr, weil Du einfach nur die geänderten Parameter
einsetzen mußt.

Jeder Lösungsweg, der frühzeitig auf spezifische Werte
zugreift und nicht sicherstellt, daß er für möglichst
viele Fälle allgemein anwendbar ist, ist unwissenschaftlich.
Die Lösung soll so allgemein wie möglich sein, damit sie
auf möglichst viele Fälle anwendbar ist.

Bei Abweichungen von diesem generischen Paradigma gab es
in der Schule wie auch erst recht bei Klausuren an der Uni
Punktabzug, sogar im Labor/praktikum/. Es ist mir als
Physiker in Fleisch und Blut übergegangen.

Physikers endgültiges Ideal ist dabei ganz bescheiden die
Weltformel, die, über eine Unzahl an Parametern gesteuert,
bereits bekannte Formeln, z. B. aus Quantendynamik und
Relativitätstheorie jeweils als Spezialfälle (wiewohl immer
noch als allgemeine Gleichung) ergibt, und somit letztlich
jedes beliebige physikalische Phänomen beschreiben kann.

Je länger ich darüber nachdenke - Differentialgleichungen
löst man allgemein und erzeugt spezielle Lösungen durch
Parametrisierung; Kant, Kritik der praktischen Vernunft:
"Handle stets so, daß die Maxime Deines Handelns als
Grundlage einer allgemeinen Gesetzgebung dienen könnte.";
die Einlassungen Hegels in der Phänomenologie des Geistes
im Kapitel "Das Diese und das Meinen" -, desto mehr tendiere
ich doch zu der Ansicht, daß das generische Paradigma keine
Geschmackssache und auch nicht auf die Naturwissenschaften
beschränkt ist.

Vielmehr ist das Prinzip, möglichst abstrakte und möglichst
universelle Lösungen auf Vorrat zu produzieren, um konkrete
Einzelfälle bei Bedarf daraus zu deduzieren, ein Konstituens
für das, was den Menschen ausmacht. Das zieht sich durch die
gesamte Geistesgeschichte.

Ein weiteres Indiz: In IQ-Tests findest Du massenhaft
Aufgaben, die darauf basieren, in im Speziellen
verschiedenen Dingen auf allgemeinerem Niveau doch noch
Ähnlichkeiten zu abstrahieren, um sie als gleichartig zu
erkennen. Die Ausprägung der Fähigkeit, sich vom Konkreten
zu lösen und einen möglichst hohen Abstraktionsgrad mit
möglichst hoher Generalisierung zu erreichen, wird hier
sogar als Maßstab für die Intelligenz des Probanden
hergenommen.***

Bezogen auf die Ausgangsfrage: Muß es denn generisch
sein? Ja, und nicht nur die Klassen, sondern jedwedes
problemorientierte Verhalten.

Du hast mich inzwischen davon überzeugt, Paul, daß fehlende
Klassengeneralisierung keine Frage des Gefallens oder
Nichtgefallens, sondern tatsächlich eine objektive
Fehlentwicklung ist.

Dafür, daß jemand, wie Du es andeutest, ein Problem lösen
will, ohne dabei gleichzeitig eine möglichst allgemein
anwendbare Lösungsschablone zu entwerfen, ist in meinem
Weltbild jetzt definitiv kein Platz mehr.

Das ist zwar nicht in Deinem Sinne, aber danke für die
Gewißheit. ;-)
Post by Paul Rohorzka
Ich würde es schade finden, wenn diese Diskussion - so
oft sie auch schon geführt wurde - nicht auf sachlicher
Ebene weitergehen würde.
Sie darf gerne auch etwas polemisch sein. An Podendorfismen
habe ich aber keinen Bedarf.

Gruß aus Mainz
Michael

***Nein, das ist /nicht/ als Beleidigung für
Meinungsabweichler gedacht. Daß es solche Aufgaben
in IQ-Tests gibt, ist ein empirisches Faktum und
möglicherweise ein Anlaß zum Nachdenken. Mehr soll
es nicht sein.
g***@web.de
2005-12-05 13:02:40 UTC
Permalink
Grüß euch!

Also erst mal:

'Dampf raus nehmen
Do Until Aggression.Level<=aggrNormal
Aggression.ReduceLevel
Loop

'Pandoras Büchse wieder schließen
On Error Resume Next ' Auch da gibt es Grundsatzdiskussionen ;-)
BoxList("Pandora").Close
If Err Then
'Konnte leider nicht geschlossen werden
Err.Clear
On Error Goto ErrHandler
'Also doch Canossa...
Poster("Gottfried").State Statement:="Entschuldigung!",
Reciever:="Michael"
End If

<Paul>
Post by Michael Zimmermann
Aber warum in aller Welt müssen sie <Objekte> generisch sein?
<Michael>
Post by Michael Zimmermann
Diese Forderung hat wenig mit Objekt oder nicht Objekt zu
tun. Ich würde auch im rein prozeduralen Bereich erwarten,
daß eine Funktion mindestens zu einem gewissen Grad über
Parameter an verschiedene Anwendungsumgebungen angepaßt
werden kann.
Also z. B. statt eines Function-Stapels
HoleKundeVorname, HoleKundeNachname, HoleLieferantVorname,
HoleWert(Entität, Attribut)
Führt das nicht dazu, dass man ganz viel mit Variants und all den
damit verbundenen Fehlern klar kommen muss? Auch für die Lesbarkeit
ist ein sprechender Prozedurname, doch allemal besser als so
allgemeine Funktionen wie "HoleWert"... Ja, und dann kommen später die
optionalen Parameter und VBs "geniale Auto-Typ-Conversion" dazu...

Wir reden hier ständig von Generalisierung. Warum siehst du, Michael,
die Wiederverwendbarkeit *nur* Anwendungsübergreifend, ja, geradezu
weltumspannend? Ich erlebe den Vorteil von z.B. Zugriffsklassen auch
innerhalb eines Projekts, wo ich eine wiederkehrende Problemstellung
oft nur mit einer einzigen Zeile sauber und typenstreng erledigen kann.
Ich teile deinen Standpunkt, dass Klassen generalisiert sein sollten,
aber ich sehe diese Generalisierung in unterschiedlich weitgestecktem
Kontext.
Post by Michael Zimmermann
<Gottfried, der über die Stränge schlug...>
Auch das hätte nicht sein müssen.
Grober Klotz, grober Keil ist bekannt?
Entschuldigung siehe oben! Hoffentlich ist das für dich OK, den
beleidigen wollte ich dich natürlich nicht. Durch deine deutliche
Ablehnung des OOP-Zugangs und Aussagen wie "Klassenprogrammierung <ist>
recht robust und nicht sonderlich schwierig" habe ich den Schluss
gezogen, dass du dich damit nicht soviel beschäftigt hast. Die
Formulierung ging dann in die Hose - tut leid!

<Michael>
Post by Michael Zimmermann
Wenn Du ein ganz spezielles Problem zu lösen hast, laß
es bleiben.
Stelle erst alle benötigten Formeln zusammen, ermittle dann
mit Größenvariablen die gesuchte Zielgröße und setze erst
/ganz am Schluß/ die aufgabenspezifischen Zahlen (Daten)
Deiner Ausgangsfragestellung in diese allgemeine Lösung
ein.
Schreibe dieselbe in Deine Formelsammlung und habe bei
weiteren gleichartigen Problemen keine unnötige Arbeit
mehr, weil Du einfach nur die geänderten Parameter
einsetzen mußt.
Jeder Lösungsweg, der frühzeitig auf spezifische Werte
zugreift und nicht sicherstellt, daß er für möglichst
viele Fälle allgemein anwendbar ist, ist unwissenschaftlich.
Die Lösung soll so allgemein wie möglich sein, damit sie
auf möglichst viele Fälle anwendbar ist.
<Michael an anderer Stelle>
Post by Michael Zimmermann
Meine Meinung zu Assistenten und Code-Generatoren müßtest
Du aber kennen. Das ist nichts, womit man mich irgendwohin
locken kann.
Für mich ist aber gerade so ein Generator etwas wie eine "MetaFormel",
den er schafft es aus einer allgemeinen DB-Struktur eine spezielle
Lösung zu erzeugen. Ich schaffe einmal mit viel Aufwand eine
generalisierte Lösung, die ich dann in meine "Generatorsammlung"
eintrage um dann bei "weiteren gleichartigen Problemen keine unnötige
Arbeit mehr zu haben, weil ich nur die geänderten Parameter einsetzen
muss"

Außerdem schreibst du oben "möglichst viele Fälle"... Genau so meine
ich auch die Generalisierung in unterschiedlich weit gestecktem
Kontext.
Post by Michael Zimmermann
Vielmehr ist das Prinzip, möglichst abstrakte und möglichst
universelle Lösungen auf Vorrat zu produzieren, um konkrete
Einzelfälle bei Bedarf daraus zu deduzieren, ein Konstituens
für das, was den Menschen ausmacht. Das zieht sich durch die
gesamte Geistesgeschichte.
Eine 3-Schicht-Architektur, deren Daten-Schicht in hohem Maße
generalisierte Zugriffe ermöglicht, deren Business-Schicht von einem
Generator erzeugt wurde, und deren Präsentations-Schicht nur noch eine
"Hülle" (->Skin) ist, erfüllt dieses Ideal doch auch recht gut, oder?
Post by Michael Zimmermann
Bezogen auf die Ausgangsfrage: Muß es denn generisch
sein? Ja, und nicht nur die Klassen, sondern jedwedes
problemorientierte Verhalten.
Dass du ein ausgezeichneter Theoretiker bist (das meine ich gar nicht
zynisch!) ist hier eh jedem klar. Der Anspruch der totalen und
ausnahmelosen Erfüllung eines Ideals ist dir "in Fleisch und Blut"
übergegangen. Ich ("Vorrecht des Autodidakten") sehe das nicht so
streng. Wie gesagt: Wenn die Generalisierung ausreicht, dass ich
innerhalb einer komplexen Anwendung wiederkehrende Probleme besser,
sauberer und schneller lösen kann (ja sogar besser, schneller und
sauberer als mit Funktionen a la "HoleWert()"!), dann mache ich das
eben so.
Post by Michael Zimmermann
Du hast mich inzwischen davon überzeugt, Paul, daß fehlende
Klassengeneralisierung keine Frage des Gefallens oder
Nichtgefallens, sondern tatsächlich eine objektive
Fehlentwicklung ist.
Du hast dich noch nicht dazu geäußert, wie du über die .NET-Welt
denkst. Dort ist ja alles Objekt. Und der DataSet-Generator und
neuerdings die Templates sind schon großartige Werkzeuge. Alles eine
Fehlentwicklung?

Also, nix für ungut und Freundschaft!

lg
Gottfried
Michael Zimmermann
2005-12-06 14:48:49 UTC
Permalink
Hallo!
Statement:="Entschuldigung!", Reciever:="Michael"
Akzeptiert. Zumal sie mit benannten PARAMETERN daherkommt.
Im Gegenzug bekommst Du daher von mir an dieser Stelle das
Bekenntnis: Autodidakten sind sexy. ;-)
<Paul>
Post by Michael Zimmermann
Aber warum in aller Welt müssen sie <Objekte>
generisch sein?
<Michael>
Post by Michael Zimmermann
Diese Forderung hat wenig mit Objekt oder nicht Objekt
zu tun. Ich würde auch im rein prozeduralen Bereich
erwarten, daß eine Funktion mindestens zu einem
gewissen Grad über Parameter an verschiedene
Anwendungsumgebungen angepaßt werden kann.
Also z. B. statt eines Function-Stapels
HoleKundeVorname, HoleKundeNachname,
HoleLieferantVorname, HoleLieferantVorname, ... eine
HoleWert(Entität, Attribut)
Führt das nicht dazu, dass man ganz viel mit Variants und
all den damit verbundenen Fehlern klar kommen muss?
Natürlich ist Generalisierung nicht das einzige, worauf
man zu achten hat, und wenn Interessenkonflikte mit
gegenläufigen Prinzipien entstehen, muß man einen sinnvollen
Kompromiß finden.

Vererbung ist da ein sehr elegantes Prinzip, da man
gleichzeitig extrem abstrakte Basisklassen, die kaum
noch semantischen Gehalt haben, mit diese involvierenden
spezialisierten Klassen kombinieren kann. Das ist für
mich einer der wertvollsten Aspekte der Programmierung
mit Klassen, daß man so scheinbar unvereinbare Forderungen
unter einen Hut bringen kann.
Auch für die Lesbarkeit ist ein sprechender Prozedurname,
doch allemal besser als so allgemeine Funktionen wie
"HoleWert"...
Nichts gegen lesbaren Code. Aber ein gewisses geistiges
Niveau darf man bei Programmierern doch voraussetzen.
Wenn einer beim Anblick harmloser Parameter schon
Hautausschlag bekäme, würde ich eine so mathematik-
und logiklastige Tätigkeit wie Programmieren als falsche
Berufswahl ansehen.
Ja, und dann kommen später die optionalen
Parameter und VBs "geniale Auto-Typ-Conversion" dazu...
Letztere ist Teufelszeug. Option Strict tut not.
Wir reden hier ständig von Generalisierung. Warum siehst
du, Michael, die Wiederverwendbarkeit *nur*
Anwendungsübergreifend, ja, geradezu weltumspannend?
Weil ich im dritten Semester im dritten Kellergeschoß
des Instituts für theoretische Physik, Haus 3 schwören
mußte, mich mit keiner Formel zu bescheiden, die weniger
als alles erklärt. Ich mußte diesen Schwur in dreifacher
Ausfertigung mit je drei Kreuzen meines Blutes
unterzeichnen. ;-)
... Ich teile deinen Standpunkt, dass Klassen
generalisiert sein sollten, aber ich sehe diese
Generalisierung in unterschiedlich weitgestecktem
Kontext.
Wenn die Zugriffsklasse mehr oder weniger leer ist, weil
sie nur eine generische Produktivklasse umhüllt, kann man
darüber nachdenken (s. u., ich lasse mich über diesen Aspekt
bei Prozeduren näher aus).

Da ich mit Entität("Kunde").Eigenschaft("Vorname") keinerlei
Problem habe, wäre mir das Schreiben solcher Wrapper aber
zu viel unnötige Arbeit.

Zumal ich ein Verfechter (und noch eine Grundsatzdiskussion
;-) ) von exzessiven Variablengebrauch bin:

Dim Kunde As Entity

Set Kunde = New Entity
Kunde.Source = "tblKunde"
Kunde.Id = Me.Controls("idKd").Value
etc.

Um sprechende Namen im Code zu haben, muß der Name der
Klasse nicht selbst sprechend sein, es genügt, die benutzte
Variable so zu nennen.

(Der Ehrlichkeit halber sei gestanden, daß sprechende Namen
für mich meist t, z, i, n lauten ;-) )
Post by Michael Zimmermann
<Gottfried, der über die Stränge schlug...>
Auch das hätte nicht sein müssen.
Grober Klotz, grober Keil ist bekannt?
Entschuldigung siehe oben! Hoffentlich ist das für dich
OK, ...
Ja, klar.
... den beleidigen wollte ich dich natürlich nicht.
Ich hatte mich schon gewundert.
Durch deine deutliche Ablehnung des OOP-Zugangs ...
Wie kommst Du denn nur darauf? Ich krittele natürlich
ständig daran herum. Durch Meckerei werden Schwächen
aufgezeigt, deren Beseitigung oder Vermeidung dann zur
Verbesserung des Konzepts beiträgt.

Ich meckere nur über Dinge, mit denen ich mich beschäftige
und die mich interessieren. Sonst bräuchte ich zum einen
nicht zu meckern und wüßte zum anderen ja auch gar nicht,
worüber.

Vorbehaltlose Begeisterung ist immer auch Stillstand. Wenn
etwas konstruktiv war, war's eine Kritik.
... und Aussagen wie "Klassenprogrammierung <ist> recht
robust und nicht sonderlich schwierig" ...
Eine Wasser-Klasse siedet genauso bei 100° wie eine
Wasser-Function.

Sei doch froh, wenn das jemand so deutlich sagt. Ich habe
in Kursen immer wieder festgestellt, daß Teilnehmer den
Umgang mit Klassen gar nicht erst lernen wollten, weil das
ja soo schwer ist und es beim anstehenden Problem ja auch
ohne geht.

Wenn einer, weil man ihm diesen unsinnigen Respekt genommen
hat, erstmal eine Sammlung von verwandten Subs und Functions
in eine Klasse packt, ist das zwar nicht der Schatz der
Zwerge, aber ein problemloser und nicht sonderlich
schwieriger erster Schritt. Und: Es ist eine Klasse.

Bald schon kommt er auf die Idee, die Sub SetValue und
die Function GetValue als /eine/ Property Value anzusehen,
weil er die strukturale Gleichheit von Property Let mit
einer Sub und Property Get mit einer Function erkennt.

Irgendwann geht ihm dann auf, wie praktisch es ist, im
Initialize- und Terminate-Ereignis automatisch Code
ausführen zu können.

Irgendwann drängt es ich auf, Klassen als Datentyp von
Eigenschaften zu verwenden und Objekthierarchien zu
bauen, nachdem er das Mysterium von _NewEnum entschleiert
hat, Ereignisse zu nutzen, nachzulesen, was Kapselung
bedeutet und warum sie wichtig ist, sich über Polymorphismus
Gedanken zu machen und über die fehlende Vererbung zu
jammern.

Warum willst Du es denn einem Novizen verleiden, sich
überhaupt mit dem Thema zu befassen, indem Du das Pferd
von hinten aufzäumst? Soll man zum Einstieg wirklich sagen,
daß er die Finger von Klassen lassen soll, solange er sich
nicht mit Weak Referencies befaßt hat, obwohl sein aktuelles
Problem (und seine nächsten zwanzig Probleme) vielleicht gar
keine reziproken Objektbezüge braucht?

Wie bringst Du Deinen Erstklässlern das Lesen bei? Mit Hegel
und Arno Schmidt?
... habe ich den Schluss gezogen, dass
du dich damit nicht soviel beschäftigt hast.
Da ich einer Deiner "Lehrer" war, der, der Dir damals
beigebracht hat, wie man in VBA mittels Notepad, der
besten IDE aller Zeiten, die Automatische Enumeration und
die Prozedurattribute festlegt ("Auflistungsklasse und
VBA", weißt Du noch?), nahm ich an, Du wüßtest, daß ich
mich damit beschäftigt habe. Vor diesem Hintergrund
hatte ich es einfach als plumpe Anmache aufgefaßt.

Hatte mich etwas erstaunt, weil es nicht zu Dir paßt,
aber wenn's da steht...
<Michael>
Post by Michael Zimmermann
Wenn Du ein ganz spezielles Problem zu lösen hast, laß
es bleiben.
Stelle erst alle benötigten Formeln zusammen, ermittle
dann mit Größenvariablen die gesuchte Zielgröße und
setze erst /ganz am Schluß/ die aufgabenspezifischen
Zahlen (Daten) Deiner Ausgangsfragestellung in diese
allgemeine Lösung ein.
Schreibe dieselbe in Deine Formelsammlung und habe bei
weiteren gleichartigen Problemen keine unnötige Arbeit
mehr, weil Du einfach nur die geänderten Parameter
einsetzen mußt.
Jeder Lösungsweg, der frühzeitig auf spezifische Werte
zugreift und nicht sicherstellt, daß er für möglichst
viele Fälle allgemein anwendbar ist, ist
unwissenschaftlich. Die Lösung soll so allgemein wie
möglich sein, damit sie auf möglichst viele Fälle
anwendbar ist.
<Michael an anderer Stelle>
Post by Michael Zimmermann
Meine Meinung zu Assistenten und Code-Generatoren
müßtest Du aber kennen. Das ist nichts, womit man mich
irgendwohin locken kann.
Für mich ist aber gerade so ein Generator etwas wie eine
"MetaFormel", den er schafft es aus einer allgemeinen
DB-Struktur eine spezielle Lösung zu erzeugen.
Wundert es Dich, wenn ich Dir sage, daß ich die Schrulle
habe, Rechenergebnisse von Taschenrechnern im Kopf
nachzurechnen, weil ich den Dingern nicht traue?

Per Code erzeugter Code ... schauder.
Ich schaffe einmal mit viel Aufwand eine generalisierte
Lösung, die ich dann in meine "Generatorsammlung"
eintrage um dann bei "weiteren gleichartigen Problemen
keine unnötige Arbeit mehr zu haben, weil ich nur die
geänderten Parameter einsetzen muss"
Wenn Du damit automatisch auf eine geänderte DB-Struktur
reagierst, gibt das zwar keinen Freispruch, aber immerhin
mildernde Umstände. ;-) Ich bevorzuge dennoch die klassische
Klassen- oder Funktionsbibliothek.
Außerdem schreibst du oben "möglichst viele Fälle"...
Genau so meine ich auch die Generalisierung in
unterschiedlich weit gestecktem Kontext.
Schon okay, aber wenn Du bis in die spezifische Datenebene
hineingehst, ist das keine Generalisierung mehr.
Post by Michael Zimmermann
Bezogen auf die Ausgangsfrage: Muß es denn generisch
sein? Ja, und nicht nur die Klassen, sondern jedwedes
problemorientierte Verhalten.
...
Wie gesagt: Wenn die Generalisierung ausreicht, dass ich
innerhalb einer komplexen Anwendung wiederkehrende
Probleme besser, sauberer und schneller lösen kann (ja
sogar besser, schneller und sauberer als mit Funktionen a
la "HoleWert()"!), dann mache ich das eben so.
"Ich mache das eben so" <> "Man sollte das so machen"

Ich komme Dir an dieser Stelle so weit entgegen, daß ich
solche Spezialisierungen zu Abkürzungszwecken für akzeptabel
halte, wenn sie keine eigene Intelligenz enthalten, sondern
auschließlich der Kapselung des Aufrufs der generischen
Prozedur/Klasse dienen.

Das Grundproblem hatten wir schon zu Anfang genannt, und
Du hast es dort auch solches eingesehen:

Sobald Funktionalitäten mehrfach vorliegen (Klassen, die
die Tabellenstruktur nachmodellieren, etwas aufwendigere
"Hole"-funktionen), müssen Code-Änderungen an vielen Stellen
womöglich von verschiedenen Personen vorgenommen werden.

Dieser Vorgang ist immer ein Fehlerrisiko (und unnötige
Arbeit).

Nochmal ein Beispiel zu Hole: Der hochspezialisierte
Funktionsstapel enthält in jeder der vielen Prozeduren
einen Sortieralgorithmus. Dieser soll irgendwann auf
einen effizienteren Algorithmus umgestellt werden.

Stellt sich bei vielen Prozeduren/Klassen die Frage: Ist
die Aktualisierung auch bei keinem der in etliche Dlls
verteilten Vorkommen vergessen worden?
Post by Michael Zimmermann
Du hast mich inzwischen davon überzeugt, Paul, daß
fehlende Klassengeneralisierung keine Frage des
Gefallens oder Nichtgefallens, sondern tatsächlich
eine objektive Fehlentwicklung ist.
Du hast dich noch nicht dazu geäußert, wie du über die
.NET-Welt denkst.
Finster. Ich sehe wenige Verbesserungen, denen eine Legion
von Unnützem entgegensteht.
Dort ist ja alles Objekt.
Nein, zum Glück nicht. Das ist als Lippenbekenntnis
herbeigequält. Ein echtes Objekt ist immer explizit im
Code vom Programmierer aus der entsprechenden Klasse
zu instanzieren.

Daß Du in .net einen String benutzen kannst, ohne daß Du
vorher explizit einen Konstruktor aufgerufen haben mußt
bzw. ein Mutterobjekt brauchst, wovon Du den String als
Eigenschaft ableitest, oder daß Du die Zuweisung t = "Hallo"
machen kannst, ohne eine Property anzugeben, die diese
Zuweisung aufnehmen soll, sind klare Indizien, daß es kein
echtes Objekt ist.

Sag jetzt nichts von Default-Properties. Das ist beim
String die schreibgeschützte Chars()-Eigenschaft.

"Hallo" ist auch kein "literales Objekt", daß man das als
Objektzuweisung auffassen könnte, denn "Hallo".Length
z. B. ist ein Fehler.

Wie kommt also das "Hallo" in das String-Objekt? Vielleicht
wird es ja heimlich ganz unobjektig als Byte-Vektor an eine
Speicheradresse geschrieben wie bei einem /Werte/typ?

Es heißt dann ja etwas tricky "nativer Typ", die Bezeichnung
"primitives Objekt" habe ich dafür auch schon gelesen; eine
freundliche Umschreibung für "kein Objekt".

Daß es auch in der Objektorientierung irgendwann einen
Abschluß geben muß, der kein Objekt ist, erscheint mir
evident: Irgendwo muß der regressus infinitum, der entsteht,
wenn Prädikate selbst wieder Objekte sind, ja ein Ende
finden, weil man bei Prädikaten erster Stufe, die selbst
nicht mehr Objekt sein können, angelangt ist.

Wenn Du das ganz ernst nimmst, sieht das so aus:

(Angenommen,die String-Klasse hätte eine Value-Eigenschaft,
die selbst ein Objekt der Klasse String ergibt)

Console.WriteLine(t.Value.Value.Value.Value...)

Was tun? Default? Gib's nur einmal, wehe, wenn so ein
Dilemma zweifach auftaucht. Außerdem: Prinzipienreiterische
Objektfanatiker benutzen keine Defaults.

Wenn die Blätter (Endglieder in Hierarchien) in den
Objekteigenschaften primitive Datentypen sind, also keine
Objekte mehr, dann ist an dieser Stelle sofort Schluß:

Console.WriteLine(t.Value)

Verstehe das jetzt nicht wieder als Objektverteufelung. Ich
mein's nur gut. In einer guten objektorientierten Sprache
soll es auch Nicht-Objekt-Datentypen und Prozeduren geben.

Ich meine, mit .net hat man aus Marketinggründen das Kind
mit dem Bad ausgeschüttet. Ich kenne nur wenige, die voller
Begeisterung umgehend ihr VB.Classic dafür weggeschmissen
hätten. Die meisten sind skeptisch und quälen sich damit,
weil man ja irgendwie am Ball bleiben muß.

Eine konsequente Weiterentwicklung des klassischen VB
mit Verstärkung der Objektfähigkeiten unter Beibehaltung
der prozeduralen Möglichkeiten wäre die bessere Wahl
gewesen. Revolutionäre Änderungen tun nie gut. Bei jeder
Revolution gibt es einen Haufen Leichen, und die Revoluzzer
machen nach wenigen Jahren genau das gleiche, was sie den
Reaktionären vorgeworfen haben.

Der Inbegriff der objektorintieten Sprachen C++ kommt seit
Urzeiten mit seinem prozeduralen Kern C problemlos klar.
Und der DataSet-Generator und neuerdings die Templates
sind schon großartige Werkzeuge. Alles eine
Fehlentwicklung?
Ich halte das DataSet-Prinzip und die dahinterstehende
Idee des Datenbank-Handlings in der Tat für eine einzige
Katastrophe. Nein, /nicht/, weil es Objekte sind. ;-)

Das gesamte DataSet-Umfeld entspricht weder in seiner
Struktur noch in seiner Begrifflichkeit der mathematischen
Theorie der Tupelmengen.

Und es entspricht auch nicht der Anwendungsarchitektur, die
mir - natürlich dann nicht mit Jet - vorschwebt: Ein
allmächtiger Server, der sämtliche dummen Clients ständig
unter Kontrolle hat. Ich will keine unverbundene
RAM-Datenbank.

Die Objekthierarchie ist schwammig. Ich erwarte saubere
Strukturen, wie z. B. in Excel

set a = New Application
Set b = a.Workbooks(i) oder a.Workbooks.Add
set s = b.WorkSheets(i) oder s.Worksheets.Add
set r = s.Range("A1")
v = r.Value

Es gibt kein New Value, kein New Range etc.:

Erst Anwendung, dann Workbook usw. Es gibt zu dieser
Abfolge keine Syntax-Varanten, sondern genau einen
vorgeschriebenen Weg: Klares Konzept.

Es gibt nur einen Schönheitsfehler, daß man auch ein
Workbook erzeugen kann, und die Anwendung sich davon
ableitet. Das ist häßlich, aber auch die einzige Macke.

Bei .net, speziell ADO.net ist es oft wie auch schon
bei ADO:

Es gibt keine klare Hierarchie, sondern ein klebriges
Spinnennetz: Man kann bei allen möglichen Objekten
einsteigen und andere davon ableiten. Daß dieselbe
Funktionalität auf etliche, deutlich unterschiedliche
Weisen erreicht werden kann, ist für die Entwicklung
ein Übel. Jeder muß jede Syntax-Variante kennen, weil
er sonst den Code anderer nicht versteht. Zumindest
gibt es einen unnötigen Zeitaufwand beim Einarbeiten
bzw. Lernen, der vermieden würde, wenn jeder genau gleich
programmieren müßte, weil es einfach nicht anders geht.

Nochmal: Es geht nicht um Klassenverteufelung, es geht um
das rechte Maß. Klassen sind ebensosehr in der modernen
Softare-Entwicklung unverzichtbar, wie sie andererseits
keine alleinige Heilslehre sind. (Letztere Auffassung
unterstelle ich Dir, Gottfried, im Stillen immer ein
bißchen.)

Jesus hat schon vor ca. 2000 Jahren prophetisch gesagt:

Die Klassen sind um des Programmierers willen da, und nicht
der Programmierer um der Klassen willen.

Gruß aus Mainz
Michael
Gottfried Lesigang
2005-12-06 22:42:23 UTC
Permalink
Grüß dich Michael!
Post by Michael Zimmermann
Im Gegenzug bekommst Du daher von mir an dieser Stelle das
Bekenntnis: Autodidakten sind sexy. ;-)
Na, das /freut/ mich jetzt aber ;-)
Post by Michael Zimmermann
Post by g***@web.de
<Paul>
Post by Michael Zimmermann
Aber warum in aller Welt müssen sie <Objekte>
generisch sein?
<Michael>
Post by Michael Zimmermann
Also z. B. statt eines Function-Stapels
HoleKundeVorname, HoleKundeNachname,
HoleLieferantVorname, HoleLieferantVorname, ... eine
HoleWert(Entität, Attribut)
<Gottfried>
Post by Michael Zimmermann
Post by g***@web.de
Führt das nicht dazu, dass man ganz viel mit Variants und
all den damit verbundenen Fehlern klar kommen muss?
<Michael>
Post by Michael Zimmermann
Natürlich ist Generalisierung nicht das einzige, worauf
man zu achten hat, und wenn Interessenkonflikte mit
gegenläufigen Prinzipien entstehen, muß man einen sinnvollen
Kompromiß finden.
Um bei deinem Beispiel zu bleiben: Ich habe natürlich auch keine unzähligen
"Hole..."-Funktionen. Bei mir gibt es eine "CreateKundeByDAORs" und eine
"CreateKundeByID". Erstere tut nichts anderes als den gerade aktuellen
Record eines DAO-Rs in die privaten Variablen der Klasse einzutragen. Ich
benutze sie z.B. wenn ich ein Rs durchlaufe, oft sogar immer mit derselben
Objekt-Instanz. Die zweite macht nichts anderes, als das entsprechende
SELECT-Statement zu bilden, das Rs zu laden und dieses dann der ersten zu
übergeben. Diese Funktion benutze ich dort, wo ich einmalig ein Objekt über
seine ID aufbauen will.

Statt all den "Hole..." Funktionen gibt es also - um bei deinem Ausdruck zu
bleiben - eine "HoleKunde(ID As Long) As clsKunde"

Dim tmpK As clsKunde
Set tmpK = CreateKundeByID(123)
With tmpK
Debug.Print .PrettyName 'Baut in der Klasse den vollen Namen mit Titel
etc. formatiert auf.
[...]
End With

Es ginge noch kürzer mit
With CreateKundeByID(123)
Aber ich bin auch ein "variabler Fetischist" ;-)

Mit einer einzigen "Hole..."-Zeile habe ich also vollen Zugriff auf alle
Feld-Werte dieser Kundenzeile. Ist es ein "Requiered"-Feld, dann ganz
typenstreng, sonst mit Variant, gelegentlich typenstreng mit einem
NULL-Substitut. Das alles geht sauber, ohne Parameter, die ich als sehr
fehleranfällig empfinde (z.B. bei Änderungen der Feldnamen).

Hat der Kunde nun z.B. einen Fremdschlüssel "MainAddressID", dann liefert
eine Property "MainAdressID" diese einfach hinaus. Es gibt aber auch eine
Property "MainAddress", die intern nichts anderes macht als "Set MainAddress
= CreateAddressByID(mMainAddressID)"

Das ermöglich z.B. im obigen "With"
Debug.Print .MainAddress.Formatted 'liefert die Adresse komplett
formatiert z.B. für Kuvert-Beschriftung
Post by Michael Zimmermann
Vererbung ist da ein sehr elegantes Prinzip, da man
gleichzeitig extrem abstrakte Basisklassen, die kaum
noch semantischen Gehalt haben, mit diese involvierenden
spezialisierten Klassen kombinieren kann. Das ist für
mich einer der wertvollsten Aspekte der Programmierung
mit Klassen, daß man so scheinbar unvereinbare Forderungen
unter einen Hut bringen kann.
Da bin ich vollkommen bei dir...
Post by Michael Zimmermann
Post by g***@web.de
Auch für die Lesbarkeit ist ein sprechender Prozedurname,
doch allemal besser als so allgemeine Funktionen wie
"HoleWert"...
Nichts gegen lesbaren Code. Aber ein gewisses geistiges
Niveau darf man bei Programmierern doch voraussetzen.
Wenn einer beim Anblick harmloser Parameter schon
Hautausschlag bekäme, würde ich eine so mathematik-
und logiklastige Tätigkeit wie Programmieren als falsche
Berufswahl ansehen.
Wie sagte Paul so schön: Der Programmierer benutzt Objekte und typenstrenge
Zugriffe über Properties um sich vor sich selbst zu schützen! ;-)
Post by Michael Zimmermann
Post by g***@web.de
Ja, und dann kommen später die optionalen
Parameter und VBs "geniale Auto-Typ-Conversion" dazu...
Letztere ist Teufelszeug. Option Strict tut not.
Auch da bin ich vollkommen bei dir!
Post by Michael Zimmermann
Post by g***@web.de
Wir reden hier ständig von Generalisierung. Warum siehst
du, Michael, die Wiederverwendbarkeit *nur*
Anwendungsübergreifend, ja, geradezu weltumspannend?
Weil ich im dritten Semester im dritten Kellergeschoß
des Instituts für theoretische Physik, Haus 3 schwören
mußte, mich mit keiner Formel zu bescheiden, die weniger
als alles erklärt. Ich mußte diesen Schwur in dreifacher
Ausfertigung mit je drei Kreuzen meines Blutes
unterzeichnen. ;-)
Die Krux der "idealen Wissenschaft" besteht doch darin, dass reale
Problemstellungen oft zu komplex sind um sie wirklich korrekt und
allgemeingültig darzustellen. Was macht dann der kluge Kopf?
Vereinfachungen, Annahmen, kurz: Er macht sich ein Modell. Dieses Modell
kann er dann sauber und vollständig beschreiben. Zu blöd, dass die Realität
sich nicht immer ans Modell halten will ;-)
Post by Michael Zimmermann
Post by g***@web.de
... Ich teile deinen Standpunkt, dass Klassen
generalisiert sein sollten, aber ich sehe diese
Generalisierung in unterschiedlich weitgestecktem
Kontext.
Wenn die Zugriffsklasse mehr oder weniger leer ist, weil
sie nur eine generische Produktivklasse umhüllt, kann man
darüber nachdenken (s. u., ich lasse mich über diesen Aspekt
bei Prozeduren näher aus).
Hier bin ich nicht bei dir! Für eine Seminarverwaltung habe ich z.B. der
Seminar-Klasse eine Function "TeilnehmerAnmelden" verpasst. Die prüft eine
ganze Reihe Vorbedingungen und trägt dann ggf. den neuen Teilnehmer in die
DB ein. Business-Logik gehört in die Business-Schicht! Und die ist in meinem
Verständnis nun mal OOP.
Post by Michael Zimmermann
Da ich mit Entität("Kunde").Eigenschaft("Vorname") keinerlei
Problem habe, wäre mir das Schreiben solcher Wrapper aber
zu viel unnötige Arbeit.
Wozu sollte man sowas auch machen? Der größte Vorteil meiner
Herangehensweise besteht neben dem schlafwandlerisch einfachen Zugriff doch
gerade in der Ausstattungen der Klassen mit Business Logik. Eine allgemeine
Klasse wie obige wäre die ideale Basisklasse - in VB *leider* ein obsoleter
Gedanke!
Post by Michael Zimmermann
Zumal ich ein Verfechter (und noch eine Grundsatzdiskussion
Ich auch (s. oben)!
Post by Michael Zimmermann
Um sprechende Namen im Code zu haben, muß der Name der
Klasse nicht selbst sprechend sein, es genügt, die benutzte
Variable so zu nennen.
Als ob es nur auf den Klassennamen ankäme. Du kannst schon davon ausgehen,
dass eine Klasse "clsKunde" und eine "clsBestellung" etwas mehr Unterschiede
aufweisen als bloß deren Namen...

<Gottfried>
Post by Michael Zimmermann
Post by g***@web.de
... und Aussagen wie "Klassenprogrammierung <ist> recht
robust und nicht sonderlich schwierig" ...
Eine Wasser-Klasse siedet genauso bei 100° wie eine
Wasser-Function.
Wie würdest du denn reagieren, wenn jemand schriebe: "Datenbankdesign ist
recht robust und eigentlich nicht sonderlich schwierig"?

<Michael>
Post by Michael Zimmermann
[Werdegang des OOPlers gesnippt]
Warum willst Du es denn einem Novizen verleiden, sich
überhaupt mit dem Thema zu befassen, indem Du das Pferd
von hinten aufzäumst? Soll man zum Einstieg wirklich sagen,
daß er die Finger von Klassen lassen soll, solange er sich
nicht mit Weak Referencies befaßt hat, obwohl sein aktuelles
Problem (und seine nächsten zwanzig Probleme) vielleicht gar
keine reziproken Objektbezüge braucht?
Schon gut! Aber der OP hat da ein konkretes Projekt, das offenbar recht
komplex und nebenbei wohl nicht sehr professionell aufgebaut ist. Ich fände
es keine so gute Idee in diesem Fall OOP zu programmieren, wenn man damit
bis dahin noch absolut unerfahren ist.
Post by Michael Zimmermann
Wie bringst Du Deinen Erstklässlern das Lesen bei? Mit Hegel
und Arno Schmidt?
Nein, die kommen aber auch nicht auf mich zu, weil ein Verlag sie gebeten
hat ein Buch zu überarbeiten ;-)
Post by Michael Zimmermann
[Generatoren vs. Formeln]
Wundert es Dich, wenn ich Dir sage, daß ich die Schrulle
habe, Rechenergebnisse von Taschenrechnern im Kopf
nachzurechnen, weil ich den Dingern nicht traue?
Eigentlich nicht ;-)
Post by Michael Zimmermann
Per Code erzeugter Code ... schauder.
Alles tippen müssen ... schauderer!
Post by Michael Zimmermann
Post by g***@web.de
Ich schaffe einmal mit viel Aufwand eine generalisierte
Lösung, die ich dann in meine "Generatorsammlung"
eintrage um dann bei "weiteren gleichartigen Problemen
keine unnötige Arbeit mehr zu haben, weil ich nur die
geänderten Parameter einsetzen muss"
Wenn Du damit automatisch auf eine geänderte DB-Struktur
reagierst, gibt das zwar keinen Freispruch, aber immerhin
mildernde Umstände. ;-) Ich bevorzuge dennoch die klassische
Klassen- oder Funktionsbibliothek.
"Bevorzugen" klingt schon nicht mehr ganz so absolut ;-)
Post by Michael Zimmermann
Post by g***@web.de
Außerdem schreibst du oben "möglichst viele Fälle"...
Genau so meine ich auch die Generalisierung in
unterschiedlich weit gestecktem Kontext.
Schon okay, aber wenn Du bis in die spezifische Datenebene
hineingehst, ist das keine Generalisierung mehr.
An der Stelle will ich doch gar keine *totale* Generalisierung! Mir reicht
es - wie gesagt - wenn ich bei wiederkehrenden Problemen (vielleicht sogar
innerhalb nur eines einzigen Projekts!) einen Vorteil habe. Zugriffsklassen
(erweitert mit Business-Logik - wie oben beschrieben) kommen in jeder DB
sinnvoll zum Einsatz. Sinnvoll können sie aber nur sein, wenn sie eben
*nicht* generalisiert sind. Ich will ja ganz konkrete Aufgabe damit lösen!
Post by Michael Zimmermann
Ich komme Dir an dieser Stelle so weit entgegen, daß ich
solche Spezialisierungen zu Abkürzungszwecken für akzeptabel
halte, wenn sie keine eigene Intelligenz enthalten, sondern
auschließlich der Kapselung des Aufrufs der generischen
Prozedur/Klasse dienen.
Wie ich schon sagte: Business-Logik gehört IMO in die Business-Schicht...
Post by Michael Zimmermann
Sobald Funktionalitäten mehrfach vorliegen (Klassen, die
die Tabellenstruktur nachmodellieren, etwas aufwendigere
"Hole"-funktionen), müssen Code-Änderungen an vielen Stellen
womöglich von verschiedenen Personen vorgenommen werden.
In einem früheren Projekt habe ich konsequent ungebunden alles über ein
Objektmodell realisiert. Das Programm ist noch heute im Dauereinsatz und
wird laufend erweitert. Heute würde ich das so nicht mehr machen. Vor allem
das Zurückschreiben des Contents ist ein recht heikler Prozess. Deshalb
benutze ich meine Klassen heute fast ausschließlich nur lesend.
Post by Michael Zimmermann
Nochmal ein Beispiel zu Hole: Der hochspezialisierte
Funktionsstapel enthält in jeder der vielen Prozeduren
einen Sortieralgorithmus. Dieser soll irgendwann auf
einen effizienteren Algorithmus umgestellt werden.
Wie kommst du eigentlich darauf, dass ich so einen Funktionsstapel benutze?
Was hat das mit OOP zu tun? Ich käme nie auf die Idee einen
Sortieralgorithmus in mehreren Routinen redundant zu implementieren. Wenn so
was überhaupt gebraucht wird, dann gibts dafür natürlich eine eigene Klasse
;-)
Post by Michael Zimmermann
Stellt sich bei vielen Prozeduren/Klassen die Frage: Ist
die Aktualisierung auch bei keinem der in etliche Dlls
verteilten Vorkommen vergessen worden?
Mir stellt sich diese Frage in der Form sicher nicht...
Post by Michael Zimmermann
Post by g***@web.de
Dort [in .NET] ist ja alles Objekt.
Nein, zum Glück nicht. Das ist als Lippenbekenntnis
herbeigequält. Ein echtes Objekt ist immer explizit im
Code vom Programmierer aus der entsprechenden Klasse
zu instanzieren.
Ich habe mich unsauber ausgedrückt. .NET unterscheidet Value-Types (am
Stack) und Reference-Types (am Heap). Die String-Klasse ist die (IMO
einzige) Ausnahme, da sie ein Reference-Type ist, sich aber wie ein
Value-Type verhält.
Post by Michael Zimmermann
Daß Du in .net einen String benutzen kannst, ohne daß Du
vorher explizit einen Konstruktor aufgerufen haben mußt
bzw. ein Mutterobjekt brauchst, wovon Du den String als
Eigenschaft ableitest, oder daß Du die Zuweisung t = "Hallo"
machen kannst, ohne eine Property anzugeben, die diese
Zuweisung aufnehmen soll, sind klare Indizien, daß es kein
echtes Objekt ist.
Sag jetzt nichts von Default-Properties. Das ist beim
String die schreibgeschützte Chars()-Eigenschaft.
"Hallo" ist auch kein "literales Objekt", daß man das als
Objektzuweisung auffassen könnte, denn "Hallo".Length
z. B. ist ein Fehler.
Wie kommt also das "Hallo" in das String-Objekt? Vielleicht
wird es ja heimlich ganz unobjektig als Byte-Vektor an eine
Speicheradresse geschrieben wie bei einem /Werte/typ?
Ich denke da eher an Standard-*Konstruktoren*... Aus "Hallo" lässt sich ein
Stringobjekt konstruieren und dieses kann dann "t" zugewiesen werden... In
.NET braucht es ja kein "Set".
Post by Michael Zimmermann
Verstehe das jetzt nicht wieder als Objektverteufelung. Ich
mein's nur gut. In einer guten objektorientierten Sprache
soll es auch Nicht-Objekt-Datentypen und Prozeduren geben.
Gibt es ja auch...
Post by Michael Zimmermann
Der Inbegriff der objektorintieten Sprachen C++ kommt seit
Urzeiten mit seinem prozeduralen Kern C problemlos klar.
Hat nicht auch C++ (es ist lange her, dass ich mich damit spielte...)
Standardkonstruktoren? Also Konstruktoren, die als einzigen Parameter eine
Variable eines bestimmten Typs übernehmen um daraus den Content der Klasse
zu bilden. Ich bilde mir ein, dass so genau das gleiche erreicht werden kann
wie bei t="hallo"...
Post by Michael Zimmermann
Post by g***@web.de
Und der DataSet-Generator und neuerdings die Templates
sind schon großartige Werkzeuge. Alles eine
Fehlentwicklung?
Ich halte das DataSet-Prinzip und die dahinterstehende
Idee des Datenbank-Handlings in der Tat für eine einzige
Katastrophe. Nein, /nicht/, weil es Objekte sind. ;-)
Das gesamte DataSet-Umfeld entspricht weder in seiner
Struktur noch in seiner Begrifflichkeit der mathematischen
Theorie der Tupelmengen.
Und es entspricht auch nicht der Anwendungsarchitektur, die
mir - natürlich dann nicht mit Jet - vorschwebt: Ein
allmächtiger Server, der sämtliche dummen Clients ständig
unter Kontrolle hat. Ich will keine unverbundene
RAM-Datenbank.
Das muss man ja nicht so machen...
Post by Michael Zimmermann
Die Objekthierarchie ist schwammig. Ich erwarte saubere
Strukturen, wie z. B. in Excel
Eines darf man nicht vergessen: Excel ist in tausenden Stunden für einen
Massenmarkt konzipiert. Es bietet seine Objekte nach außen für die
"Fernsteuerung" an. Myriaden von Entwicklern nutzen diese stabile und
weitgehend fehlerfreie Plattform. Hier brauche ich naturgemäß ein sehr
generalisiertes und durchdachtes Konzept. Meine Projekte haben so etwas
bisher noch nicht gebraucht...
Post by Michael Zimmermann
set a = New Application
Set b = a.Workbooks(i) oder a.Workbooks.Add
set s = b.WorkSheets(i) oder s.Worksheets.Add
set r = s.Range("A1")
v = r.Value
Soviel zu den sprechenden Namen ;-) Aber du hattest dich oben eh schon
geoutet...
Meine Klassen sind stets "NotCreatable" oder "Private". In der
Objekthierarchie gibt es FactoryFunctions oder -Properties "nach unten". Das
empfinde ich - so wie du - als guten Stil.
Post by Michael Zimmermann
Erst Anwendung, dann Workbook usw. Es gibt zu dieser
Abfolge keine Syntax-Varanten, sondern genau einen
vorgeschriebenen Weg: Klares Konzept.
Da bin ich wieder voll bei dir.
Post by Michael Zimmermann
Nochmal: Es geht nicht um Klassenverteufelung, es geht um
das rechte Maß. Klassen sind ebensosehr in der modernen
Softare-Entwicklung unverzichtbar, wie sie andererseits
keine alleinige Heilslehre sind. (Letztere Auffassung
unterstelle ich Dir, Gottfried, im Stillen immer ein
bißchen.)
Auch da bin ich bei dir ;-)
Post by Michael Zimmermann
Die Klassen sind um des Programmierers willen da, und nicht
der Programmierer um der Klassen willen.
... und dann fuhr er fort: "Ich bin das Licht und die Wahrheit. Du sollst
dir von mir kein idealisiertes Modell machen!"

lg aus Wien
Gottfried
Bodo Greiner
2005-12-07 10:13:59 UTC
Permalink
Hallo Gottfried,

Deine Ausführungen sind sehr interessant! Ich hoffe, ich habe das nicht
irgendwo überlesen: Wie würde man Mehrbenutzerbetrieb regeln? Geht das
einfach oder kompliziert? Hättest Du dazu ein paar Stichwörter? (Falls ja,
programmiere ich meine nächste DB mit Klassen, ich versprech's :-)

Gruß, Bodo
Gottfried Lesigang
2005-12-07 18:43:14 UTC
Permalink
Grüß dich Bodo!
Post by Bodo Greiner
Deine Ausführungen sind sehr interessant! Ich hoffe, ich habe das nicht
irgendwo überlesen: Wie würde man Mehrbenutzerbetrieb regeln? Geht das
einfach oder kompliziert?
Naja, wenn du die Klassen nur lesend benutzt, gibt es da eigentlich keine
Probleme. Wie schon geschrieben, habe ich ein (großes) Projekt sehr
konsequent VB-OOP und dann sogar noch komplett ungebunden gemacht. Das würde
ich heute *so* nicht wieder machen ;-) Da gab es dann große Probleme beim
Zurückschreiben bei Zugriffskonflikten etc. Das Ding läuft zur Zufriedenheit
aller und ich bin froh, dass keiner unter die Haube guckt...

Bei mir hat grundsätzlich jede Tabelle die Felder
InsertedBy - Long
InsertTimeStamp - Date
UpdatedBy
UpdateTimeStamp
DeletedBy
DeleteTimeStamp

Die erwähnte Form-Behaviour-Klasse kümmert sich zentral darum, dass diese
Felder immer gesetzt werden. Um festzustellen ob ein Datensatz von jemand
anderen verändert wurde, genügt es dann den "UpdateTimeStamp" und ggf. den
"DeleteTimeStamp" zu vergleichen. Das gilt natürlich nur dann, wenn kein
"fremder" Client an die Daten geht...

Eine allgemeine Möglichkeit bestünde darin, z.B. die Kunden-Klasse mit einer
"CompareTo(K As clsKunde) As Boolean" auszustatten, wo der ganze Content
verglichen wird. So genügt es im Formular z.B. per Timer immer eine *neue*
Instanz desselben Kunden-Objekts zu laden und mit dem gerade bearbeiteten
Stand zu vergleichen. Aber mal ehrlich: Gerade das macht Access soch eh sehr
gut...
Post by Bodo Greiner
Hättest Du dazu ein paar Stichwörter? (Falls ja, programmiere ich meine
nächste DB mit Klassen, ich versprech's :-)
Tut mir leid, da ich nicht einmal das Problem sehe ;-) Willkommen im Club!
Bei uns ist es echt KLASSE!

lg
Gottfried
Gottfried Lesigang
2005-12-07 10:48:03 UTC
Permalink
Hab was vergessen...
Post by Gottfried Lesigang
Um bei deinem Beispiel zu bleiben: Ich habe natürlich auch keine
unzähligen "Hole..."-Funktionen. Bei mir gibt es eine "CreateKundeByDAORs"
und eine "CreateKundeByID". Erstere tut nichts anderes als den gerade
aktuellen Record eines DAO-Rs in die privaten Variablen der Klasse
einzutragen.
Das Objekt selbst braucht dafür natürlich eine "SetContentByDAORs(Rs As
DAO.Recordset)", da ich die Properties iaR nur als "Get" ausführe und *nur*
so die Werte setzen *kann*. Diese Sub wird dann von Create...ByDAORs
genutzt. Also:

Public Function CreateKundeByDAORs(Rs As DAO.Recordset) As clsKunde
Dim tmpK As clsKunde
Set tmpK = New clsKunde
Call tmpK.SetContentByDAORs(Rs)
Set CreateKundeByDAORs = tmpK
End Function
Post by Gottfried Lesigang
Ich benutze sie z.B. wenn ich ein Rs durchlaufe, oft sogar immer mit
derselben Objekt-Instanz.
Da habe ich dann eine einzige Objekt-Instaz, deren Inhalt ich nach jedem
"Rs.MoveNext" einfach und blitzschnell mit "SetContentByDAORs" anpasse. Das
ist IMO die schnellste, sicherste und sauberste Parameterübergabe...

lg
Gottfried
Paul Rohorzka
2006-01-16 16:41:18 UTC
Permalink
Hallo Michael!
Post by Michael Zimmermann
Post by g***@web.de
Post by Michael Zimmermann
Also z. B. statt eines Function-Stapels
HoleKundeVorname, HoleKundeNachname,
HoleLieferantVorname, HoleLieferantVorname, ... eine
HoleWert(Entität, Attribut)
Führt das nicht dazu, dass man ganz viel mit Variants und
all den damit verbundenen Fehlern klar kommen muss?
Natürlich ist Generalisierung nicht das einzige, worauf
man zu achten hat, und wenn Interessenkonflikte mit
gegenläufigen Prinzipien entstehen, muß man einen sinnvollen
Kompromiß finden.
Halleluja, genau darum geht's!
Post by Michael Zimmermann
Vererbung ist da ein sehr elegantes Prinzip, da man
gleichzeitig extrem abstrakte Basisklassen, die kaum
noch semantischen Gehalt haben, mit diese involvierenden
spezialisierten Klassen kombinieren kann. Das ist für
mich einer der wertvollsten Aspekte der Programmierung
mit Klassen, daß man so scheinbar unvereinbare Forderungen
unter einen Hut bringen kann.
Schön, aber nun einmal in unserem Kontext nicht verfügelich.
Post by Michael Zimmermann
Post by g***@web.de
Auch für die Lesbarkeit ist ein sprechender Prozedurname,
doch allemal besser als so allgemeine Funktionen wie
"HoleWert"...
Nichts gegen lesbaren Code. Aber ein gewisses geistiges
Niveau darf man bei Programmierern doch voraussetzen.
Wenn einer beim Anblick harmloser Parameter schon
Hautausschlag bekäme, würde ich eine so mathematik-
und logiklastige Tätigkeit wie Programmieren als falsche
Berufswahl ansehen.
Darum geht's nicht. Es geht darum, Fehlerquellen auszuschließen. Auch du
wirst /ernsthaft/ deine Anwendungen nicht in Assembler schreiben wollen.
Post by Michael Zimmermann
Post by g***@web.de
... Ich teile deinen Standpunkt, dass Klassen
generalisiert sein sollten, aber ich sehe diese
Generalisierung in unterschiedlich weitgestecktem
Kontext.
Wenn die Zugriffsklasse mehr oder weniger leer ist, weil
sie nur eine generische Produktivklasse umhüllt, kann man
darüber nachdenken (s. u., ich lasse mich über diesen Aspekt
bei Prozeduren näher aus).
Und viel mehr tut sie nicht. Sie stellt im Wesentlichen sicher, dass die
Tabellen- und Feldnamen nicht (oder überall konsequent) falsch sind. Im
Inneren werkt ja ohnehin ein Recordset.
Post by Michael Zimmermann
Da ich mit Entität("Kunde").Eigenschaft("Vorname") keinerlei
Problem habe, wäre mir das Schreiben solcher Wrapper aber
zu viel unnötige Arbeit.
Ganz im Gegenteil. Mit diesen Wrappern kann ich dank Intellisense viel
schneller und sicherer coden.
Post by Michael Zimmermann
Zumal ich ein Verfechter (und noch eine Grundsatzdiskussion
Dim Kunde As Entity
Set Kunde = New Entity
Kunde.Source = "tblKunde"
Kunde.Id = Me.Controls("idKd").Value
etc.
Um sprechende Namen im Code zu haben, muß der Name der
Klasse nicht selbst sprechend sein, es genügt, die benutzte
Variable so zu nennen.
Das ist schon klar. Die Frage ist, ob die Variable zur Laufzeit auch mit
den Daten gefüllt werden kann, oder ob irgendwo in einem String ein
falscher Tabellen- oder Feldname steht.
Post by Michael Zimmermann
Post by g***@web.de
Durch deine deutliche Ablehnung des OOP-Zugangs ...
...
Vorbehaltlose Begeisterung ist immer auch Stillstand. Wenn
etwas konstruktiv war, war's eine Kritik.
Von vobehaltloser Begeisterung kann wohl niemand berichten. Wie immer
geht's darum, das Thema möglichst gut zu kennen, um dann in der
konkreten Situation möglichst zielführende Entscheidungen treffen zu können.
Post by Michael Zimmermann
[Thema Assistenten und Codegeneratoren]
Per Code erzeugter Code ... schauder.
Auch bei der Softwareentwicklung sitzt der Fehler so gut wie immer vor
dem PC. Aus diesem Grund ist mir ein Tool, dass erprobter Weise
brauchbaren Code generiert lieber, als wenn ich immer wieder sehr
kreativ im Einbauen von Fehlern bin.
Post by Michael Zimmermann
...
Post by g***@web.de
Genau so meine ich auch die Generalisierung in
unterschiedlich weit gestecktem Kontext.
Schon okay, aber wenn Du bis in die spezifische Datenebene
hineingehst, ist das keine Generalisierung mehr.
Doch, damit generalisiere ich auf Anwendungsebene.
Post by Michael Zimmermann
Das Grundproblem hatten wir schon zu Anfang genannt, und
Sobald Funktionalitäten mehrfach vorliegen (Klassen, die
die Tabellenstruktur nachmodellieren, etwas aufwendigere
"Hole"-funktionen), müssen Code-Änderungen an vielen Stellen
womöglich von verschiedenen Personen vorgenommen werden.
Ach so? Das ist ja der Schmäh der Kapselklassen, dass ich nur in der
Klasse Anpassungen vornehme (sofern es sich nur kleine strukturelle
Änderungen handelt). Der eigentliche problemzentrierte Code kann dann
unberührt bleiben.
Post by Michael Zimmermann
Dieser Vorgang ist immer ein Fehlerrisiko (und unnötige
Arbeit).
Klar. Und genau da helfen mir meine Datenkapselklassen.
Post by Michael Zimmermann
Nochmal ein Beispiel zu Hole: Der hochspezialisierte
Funktionsstapel enthält in jeder der vielen Prozeduren
einen Sortieralgorithmus. Dieser soll irgendwann auf
einen effizienteren Algorithmus umgestellt werden.
Wo um Himmels Willen soll denn da sortiert werden? Vielleicht in einer
Listenklasse und dort spricht nichts dagegen, die Implementierung der
Sortierung einer generischen Sortierklasse durchführen zu lassen. Da
lassen sich btw mit Hilfe von Interfaces auch wunderbar andere
Algorithmen anwenden (Stichwort Strategy-Pattern).
Post by Michael Zimmermann
Stellt sich bei vielen Prozeduren/Klassen die Frage: Ist
die Aktualisierung auch bei keinem der in etliche Dlls
verteilten Vorkommen vergessen worden?
Nö, wenn wir schon von einer mehrschichtigen verteilten Anwendung
sprechen ist die Datenzugriffslogik anwendungsweit an einer genau
definierten Stelle (DLL, Server) vorhanden!
Post by Michael Zimmermann
Post by g***@web.de
Du hast dich noch nicht dazu geäußert, wie du über die
.NET-Welt denkst.
...
Post by g***@web.de
Dort ist ja alles Objekt.
Nein, zum Glück nicht. Das ist als Lippenbekenntnis
herbeigequält.
Nun ja, "es ist alles ein Objekt" sagt man gern im Zusammenhang mit
.NET, ist aber wirklich nicht ganz korrekt. Es können dort /alle/
Datentypen wie von Object abgeleitet verwendet werden. Die primitven
Typen sind das wie alle Werttypen definit nicht, können aber durch
Boxing entsprechend gekapselt werden.
Post by Michael Zimmermann
Ein echtes Objekt ist immer explizit im
Code vom Programmierer aus der entsprechenden Klasse
zu instanzieren.
Das muss aber nicht immer mittels Operator New erfolgen.
Post by Michael Zimmermann
Daß Du in .net einen String benutzen kannst, ohne daß Du
vorher explizit einen Konstruktor aufgerufen haben mußt
bzw. ein Mutterobjekt brauchst, wovon Du den String als
Eigenschaft ableitest, oder daß Du die Zuweisung t = "Hallo"
machen kannst, ohne eine Property anzugeben, die diese
Zuweisung aufnehmen soll, sind klare Indizien, daß es kein
echtes Objekt ist.
Doch, die Klasse (System.)String existiert. Die .NET-Sprachen
unterstützen hier allerdings die Wert-Semantik (relevant bei z.B.
Zuweisungen und Vergleichen).
Post by Michael Zimmermann
"Hallo" ist auch kein "literales Objekt", daß man das als
Objektzuweisung auffassen könnte, denn "Hallo".Length
z. B. ist ein Fehler.
Was meinst du mit "ist ein Fehler"? Auf Literale können sehr wohl die
Methoden und Eigenschaften der entsprechenden Typen angewandt werden.

Beispiele:
"Klaus Maria Brandauer".Substring(6, 5)
123.MaxValue
Post by Michael Zimmermann
Wie kommt also das "Hallo" in das String-Objekt? Vielleicht
wird es ja heimlich ganz unobjektig als Byte-Vektor an eine
Speicheradresse geschrieben wie bei einem /Werte/typ?
Es wird zur Laufzeit angelegt, so wie bei
Dim i As Integer
zur Laufzeit 4 Bytes reserviert werden.
Post by Michael Zimmermann
Es heißt dann ja etwas tricky "nativer Typ", die Bezeichnung
"primitives Objekt" habe ich dafür auch schon gelesen; eine
freundliche Umschreibung für "kein Objekt".
Das stimmt leider nicht.
Post by Michael Zimmermann
Daß es auch in der Objektorientierung irgendwann einen
Abschluß geben muß, der kein Objekt ist, erscheint mir
evident: Irgendwo muß der regressus infinitum, der entsteht,
wenn Prädikate selbst wieder Objekte sind, ja ein Ende
finden, weil man bei Prädikaten erster Stufe, die selbst
nicht mehr Objekt sein können, angelangt ist.
Warum? Primitive Typen müssen (nicht in .NET!) nicht zwingend skalar sein.
Post by Michael Zimmermann
(Angenommen,die String-Klasse hätte eine Value-Eigenschaft,
die selbst ein Objekt der Klasse String ergibt)
Hat sie, nur dass sie eine Methode ist und ToString() heißt.
Post by Michael Zimmermann
Console.WriteLine(t.Value.Value.Value.Value...)
Console.WriteLine(t.ToString().ToString().ToString())

geht (auch wenn's nix bringt).
Post by Michael Zimmermann
Was tun? Default? Gib's nur einmal, wehe, wenn so ein
Dilemma zweifach auftaucht. Außerdem: Prinzipienreiterische
Objektfanatiker benutzen keine Defaults.
Ist auch kein Problem, weil es die in .NET gibt's Defaults nur mehr bei
parametrisierten Eigenschaften (wie in den diversen Item()-Properties
von Auflistungsklassen). Bei obiger Value-Kette kommen sie also ohnehin
nicht in Frage. BTW, deshalb gibt es in .NET auch kein Set für
Objekt-Zuweisungen mehr.
Post by Michael Zimmermann
Wenn die Blätter (Endglieder in Hierarchien) in den
Objekteigenschaften primitive Datentypen sind, also keine
Console.WriteLine(t.Value)
Stimmt, is aber in .NET nicht so.
Post by Michael Zimmermann
Verstehe das jetzt nicht wieder als Objektverteufelung. Ich
mein's nur gut.
Danke NG-Papa, leider bist du diesbezüglich halt nicht gut genug informiert.
Post by Michael Zimmermann
In einer guten objektorientierten Sprache
soll es auch Nicht-Objekt-Datentypen und Prozeduren geben.
Im Gegenteil, aus dem OO-Blickwinkel sollte man es verteufeln, dass es
noch Werttypen gibt, was selbstverständlich aus dem technologischen
Blick absoluten Sinn macht. Mit dem Boxing/Unboxing-Mechanismus steht
hier ein sehr praktikabler Kompromiss zur Verfügung.
Post by Michael Zimmermann
Ich meine, mit .net hat man aus Marketinggründen das Kind
mit dem Bad ausgeschüttet. Ich kenne nur wenige, die voller
Begeisterung umgehend ihr VB.Classic dafür weggeschmissen
hätten. Die meisten sind skeptisch und quälen sich damit,
weil man ja irgendwie am Ball bleiben muß.
Man muss ja nicht gleich voller Begeisterung sein. Aber jetzt krampfhaft
das Böse zu suchen finde ich auch unproduktiv. Technologisch ist .NET
schon ein ziemlich kuhles Ding. Worüber man IMHO lauter schimpfen
könnte, ist die Tendenz, dass Microsoft bald in allen Bereichen unseres
Lebens zuwerke sein wird. Aber das ist ein anderes Thema.
Post by Michael Zimmermann
Eine konsequente Weiterentwicklung des klassischen VB
mit Verstärkung der Objektfähigkeiten unter Beibehaltung
der prozeduralen Möglichkeiten wäre die bessere Wahl
gewesen. Revolutionäre Änderungen tun nie gut. Bei jeder
Revolution gibt es einen Haufen Leichen, und die Revoluzzer
machen nach wenigen Jahren genau das gleiche, was sie den
Reaktionären vorgeworfen haben.
.NET wird nicht der Weisheit und Entwicklung letzter Schluss sein. Aber
zur Zeit ist es im Microsoft-Umfeld definitiv die beste Umgebung zur
Entwicklung von qualitativ hochwertiger Software.
Post by Michael Zimmermann
Der Inbegriff der objektorintieten Sprachen C++ kommt seit
Urzeiten mit seinem prozeduralen Kern C problemlos klar.
Über das "problemlos" lässt sich aber vortrefflich streiten. Der Sprache
tut's natürlich nicht weh, aber durchaus manchmal der Software, wenn
objektorientierte Konzepte durch prozedurale Querschüsse sabotiert werden.
Post by Michael Zimmermann
Post by g***@web.de
Und der DataSet-Generator und neuerdings die Templates
sind schon großartige Werkzeuge. Alles eine
Fehlentwicklung?
Ich denke, Gottfried meint hier die Generics.
Post by Michael Zimmermann
Ich halte das DataSet-Prinzip und die dahinterstehende
Idee des Datenbank-Handlings in der Tat für eine einzige
Katastrophe. Nein, /nicht/, weil es Objekte sind. ;-)
Das gesamte DataSet-Umfeld entspricht weder in seiner
Struktur noch in seiner Begrifflichkeit der mathematischen
Theorie der Tupelmengen.
Und wen beisst's? In gewissem Kontext und bei maßvoller Anwendung hat
das durchaus Sinn. Aber diese Diskussion möchte ich zumindestens hier
nicht schon wieder führen.
Post by Michael Zimmermann
Die Objekthierarchie ist schwammig. Ich erwarte saubere
Strukturen, wie z. B. in Excel
set a = New Application
Set b = a.Workbooks(i) oder a.Workbooks.Add
set s = b.WorkSheets(i) oder s.Worksheets.Add
set r = s.Range("A1")
v = r.Value
Nageh, müssen solche Argumente wirklich sein? Vielleicht liegt's daran,
dass sich in einer Tabelle keine neuen Bereiche erzeugen lassen, sondern
sich ein Range-Objekt nur auf einen per se existierenden Bereich
beziehen kann?
Post by Michael Zimmermann
Erst Anwendung, dann Workbook usw. Es gibt zu dieser
Abfolge keine Syntax-Varanten, sondern genau einen
vorgeschriebenen Weg: Klares Konzept.
Es gibt nur einen Schönheitsfehler, daß man auch ein
Workbook erzeugen kann, und die Anwendung sich davon
ableitet. Das ist häßlich, aber auch die einzige Macke.
Ohne auf die Wortwahl "ableitet" einzugehen: Warum ist das hässlich?
Manchmal interessiert mich eben ein Elternobjekt oder ein anderes
darüber liegendes (denn auch ein Worksheet oder ein Range haben eine
Application-Eigenschaft - das find ich auch nicht sehr schön).
Post by Michael Zimmermann
Bei .net, speziell ADO.net ist es oft wie auch schon
Es gibt keine klare Hierarchie,
Natürlich gibt's eine logische Abhängigkeit der Objekte.
Post by Michael Zimmermann
sondern ein klebriges
Spinnennetz: Man kann bei allen möglichen Objekten
einsteigen und andere davon ableiten.
Ich denke in einer Diskussion über OO in .NET sollten wir mit dem
Begriff "ableiten" differenzierter umgehen.
Post by Michael Zimmermann
Daß dieselbe
Funktionalität auf etliche, deutlich unterschiedliche
Weisen erreicht werden kann, ist für die Entwicklung
ein Übel.
Da hätte ich aber bitte jetzt gerne ein Beispiel. Für verschiedene
Ausgangspunkte gibt's verschiedene mehr oder weniger praktische
Lösungen. Das ist wohl in jeder Programmierumgebung so.
Post by Michael Zimmermann
Jeder muß jede Syntax-Variante kennen, weil
er sonst den Code anderer nicht versteht. Zumindest
gibt es einen unnötigen Zeitaufwand beim Einarbeiten
bzw. Lernen, der vermieden würde, wenn jeder genau gleich
programmieren müßte, weil es einfach nicht anders geht.
Das klingt so, als ob Mainz in èinem der Neuen Bundesländern läge.
Post by Michael Zimmermann
Nochmal: Es geht nicht um Klassenverteufelung, es geht um
das rechte Maß. Klassen sind ebensosehr in der modernen
Softare-Entwicklung unverzichtbar, wie sie andererseits
keine alleinige Heilslehre sind. (Letztere Auffassung
unterstelle ich Dir, Gottfried, im Stillen immer ein
bißchen.)
Mit Ausnahme des geklammerten Satzes stimme ich dir da vollkommen zu
(dafür kenne ich Gottfried zu gut).
Post by Michael Zimmermann
Die Klassen sind um des Programmierers willen da, und nicht
der Programmierer um der Klassen willen.
Keine Frage. Deshalb, liebe EntwicklerInnen: verwendet sie ausgiebig!

LG,
Paul
--
http://www.softconcept.at - Development, Solutions, Tools
http://access.primary.at - Wiener Access-Stammtisch
Michel Fouquet
2005-12-05 13:33:16 UTC
Permalink
Hallo,
Post by Michael Zimmermann
An Podendorfismen
habe ich aber keinen Bedarf.
der genannte Herr Ing. hat sich ja ziemlich schnell rar gemacht.

In Erinnerung daran kommt der tiefe Seufzer: was, schon wieder ein
ganzes Jahr vorbei!

Auch wenn's vielleicht auf Grund der Teilnehmerzahl an diesem Thread
nicht den Anschein hat: ich persönlich verfolge eure Diskussion mit
großem Interesse.

mfg,
Michel
Paul Rohorzka
2006-01-16 14:37:41 UTC
Permalink
Hallo Michael!

Auch, wenn's nun schon lange her ist, möchte ich dennoch manche Postings
in diesem Thread noch kommentieren.
Post by Michael Zimmermann
Post by Paul Rohorzka
Post by Michael Zimmermann
Ich auch. Objekte sind phantastisch, wenn sie generisch
sind.
Aber warum in aller Welt müssen sie generisch sein?
Diese Forderung hat wenig mit Objekt oder nicht Objekt zu
tun. Ich würde auch im rein prozeduralen Bereich erwarten,
daß eine Funktion mindestens zu einem gewissen Grad über
Parameter an verschiedene Anwendungsumgebungen angepaßt
werden kann.
Also z. B. statt eines Function-Stapels
HoleKundeVorname, HoleKundeNachname, HoleLieferantVorname,
HoleWert(Entität, Attribut)
Das ist für mich /als Softwareentwickler/ auf halber Strecke stehen
geblieben. Konkretisierungen dienen ja sehr oft dazu, Parameter an einem
Ort zu halten (Kapselung) und dem Softwareentwickler einige
Fehlermöglichkeiten aus der Hand zu nehmen.
Post by Michael Zimmermann
Post by Paul Rohorzka
Auch das hätte nicht sein müssen.
Grober Klotz, grober Keil ist bekannt?
Aug um Aug, Zahn um Zahn leider auch.
Post by Michael Zimmermann
Post by Paul Rohorzka
Ich überlege gerade, ob ich mich beleidigt fühlen soll.
Laß es.
Das ist keine Frage des Imperativs. [Warum fühle ich mich so schrecklich
anbiedernd, wenn ich in einer Antwort auf deine Postings ein Fremdwort
verwende? Hmm :-(] ;-)
Post by Michael Zimmermann
Post by Paul Rohorzka
Dafür schreiben doch Leute wie Thomas Möller, Gottfried
Lesigang, <tausende mehr hier einfügen>, Paul Rohorzka
und nicht zu letzt auch einige Entwickler bei Microsoft
Assistenten und Code-Generatoren!
Meine Meinung zu Assistenten und Code-Generatoren müßtest
Du aber kennen. Das ist nichts, womit man mich irgendwohin
locken kann.
Das weiß ich. Mit etwas weniger Quotegemarder wär meine Aussage
vielleicht auch noch im rechten Kontext verblieben.
Post by Michael Zimmermann
Post by Paul Rohorzka
Post by Michael Zimmermann
Wenn ich in jeder Anwendung, nur weil sie ein anderes
Thema hat, mir neue Klassenhierarchien basteln muß,
statt nur die im Lauf der Jahre zusammengekommenen
einfach mit anderen Parametern zu verwenden, weil sie
so abstrahiert sind, daß sie eigentlich immer passen,
dann habe ich den Grundgedanken von OOP ad absurdum
geführt.
Aber ich schreibe doch Software nicht um mich
asymptotisch dem Zustand anzunähern, wo ich schon alles
einmal programmiert habe, und wo ich nur mehr alles
richtig zusammenfügen muss.
Tatsächlich nicht? Verblüffend! Das ist für mich die einzig
sinnvolle Herangehensweise.
Siehe unten.
Post by Michael Zimmermann
Ich habe es schon zu Schulzeiten im Physik- und
Mathematikunterricht eingebleut bekommen und im
Wenn Du ein ganz spezielles Problem zu lösen hast, laß
es bleiben.
Stelle erst alle benötigten Formeln zusammen, ermittle dann
mit Größenvariablen die gesuchte Zielgröße und setze erst
/ganz am Schluß/ die aufgabenspezifischen Zahlen (Daten)
Deiner Ausgangsfragestellung in diese allgemeine Lösung
ein.
Auch in meiner Schulzeit und während meines Studiums wurde mir diese
Herangehensweise nähergebracht. Und das - du wirst es nicht glauben -
auch äußerst erfolgreich. Bei manchen Übungen musste ich die Nase über
vom Vortragendenden zu früh eingesetzte Zahlen rümpfen. Da bin ich einer
Meinung mit dir, dass dies die einzig seriöse Variante zur Lösung einer
mathematischen Aufgabe ist. Das liegt aber nicht zuletzt daran, dass wir
nummerisch zum einen die Verbindung zu den formalen Strukturen verlieren
und zum anderen i.A. nicht mehr exakt bleiben können.
Post by Michael Zimmermann
Schreibe dieselbe in Deine Formelsammlung und habe bei
weiteren gleichartigen Problemen keine unnötige Arbeit
mehr, weil Du einfach nur die geänderten Parameter
einsetzen mußt.
Im Sinne von Gottfrieds Antwort: was ich von einer Anwendung zur
nächsten immer mitnehme, sind die Tools, die ich mir schreibe, konkreten
Workcode nur selten.
Post by Michael Zimmermann
Jeder Lösungsweg, der frühzeitig auf spezifische Werte
zugreift und nicht sicherstellt, daß er für möglichst
viele Fälle allgemein anwendbar ist, ist unwissenschaftlich.
Mag sein, aber ich sehe mich (nocheinmal: in meiner Eigenschaft /als
Softwareentwickler/) als Ingenieur, nicht als Wissenschafter. Ich habe
eine konkrete Aufgabe zu lösen, nicht die Welt zu erklären.
Post by Michael Zimmermann
Die Lösung soll so allgemein wie möglich sein, damit sie
auf möglichst viele Fälle anwendbar ist.
Nicht wenn ich ein konkretes Problem zu lösen habe.
Post by Michael Zimmermann
Bei Abweichungen von diesem generischen Paradigma gab es
in der Schule wie auch erst recht bei Klausuren an der Uni
Punktabzug, sogar im Labor/praktikum/. Es ist mir als
Physiker in Fleisch und Blut übergegangen.
Schön, Problemlösung mittels Software erfordert IMHO manchmal andere
Zugänge. Gerade die vielen unterschiedlichen in Betracht zu ziehenden
Parameter und ihre vielen möglichen Werte stellen eine nicht zu
unterschätzende Fehlerquelle dar, sodass sich der Softwareentwickler mit
entsprechenden Methoden vor sich selbst schützen wird müssen.
Post by Michael Zimmermann
Physikers endgültiges Ideal ist dabei ganz bescheiden die
Weltformel, die, über eine Unzahl an Parametern gesteuert,
bereits bekannte Formeln, z. B. aus Quantendynamik und
Relativitätstheorie jeweils als Spezialfälle (wiewohl immer
noch als allgemeine Gleichung) ergibt, und somit letztlich
jedes beliebige physikalische Phänomen beschreiben kann.
Das ist schön für die Wissenschafter, bringt aber nix bei der
Softwareentwicklung. Wir bauen keine softwaretechnische Weltformel,
sondern befinden uns wie Newton in einem "Universum", in dem wir mit
unseren wenn auch nicht allgültigen Mitteln unsere Welt erklären können.
Für andere Aufgabenstellungen braucht es andere Werkzeuge und
Herangehensweisen.
Post by Michael Zimmermann
Je länger ich darüber nachdenke - Differentialgleichungen
löst man allgemein und erzeugt spezielle Lösungen durch
"Handle stets so, daß die Maxime Deines Handelns als
Grundlage einer allgemeinen Gesetzgebung dienen könnte.";
die Einlassungen Hegels in der Phänomenologie des Geistes
im Kapitel "Das Diese und das Meinen" -, desto mehr tendiere
ich doch zu der Ansicht, daß das generische Paradigma keine
Geschmackssache und auch nicht auf die Naturwissenschaften
beschränkt ist.
Wissen zu besitzen ist nicht zuletzt auch oft gut für die Entscheidung,
sich aus praktischen Überlegungen für eine mögliche Variante zu entscheiden.
Post by Michael Zimmermann
Vielmehr ist das Prinzip, möglichst abstrakte und möglichst
universelle Lösungen auf Vorrat zu produzieren, um konkrete
Einzelfälle bei Bedarf daraus zu deduzieren, ein Konstituens
für das, was den Menschen ausmacht. Das zieht sich durch die
gesamte Geistesgeschichte.
Womit ja ziemlich genau am Punkt Softwareentwicklung angelangt wären.
Post by Michael Zimmermann
Ein weiteres Indiz: In IQ-Tests findest Du massenhaft
Aufgaben, die darauf basieren, in im Speziellen
verschiedenen Dingen auf allgemeinerem Niveau doch noch
Ähnlichkeiten zu abstrahieren, um sie als gleichartig zu
erkennen. Die Ausprägung der Fähigkeit, sich vom Konkreten
zu lösen und einen möglichst hohen Abstraktionsgrad mit
möglichst hoher Generalisierung zu erreichen, wird hier
sogar als Maßstab für die Intelligenz des Probanden
hergenommen.***
Trotz deiner Fußnote finde ich solche Hinweise ziemlich überheblich.
Post by Michael Zimmermann
***Nein, das ist /nicht/ als Beleidigung für
Meinungsabweichler gedacht. Daß es solche Aufgaben
in IQ-Tests gibt, ist ein empirisches Faktum und
möglicherweise ein Anlaß zum Nachdenken. Mehr soll
es nicht sein.
Eigenartig, von dir eine solche Argumentation zu hören.
Post by Michael Zimmermann
Bezogen auf die Ausgangsfrage: Muß es denn generisch
sein? Ja, und nicht nur die Klassen, sondern jedwedes
problemorientierte Verhalten.
Wie du muss auch ich mich in meinen Antworten wiederholen:
Softwareentwicklung bedeutet konkrete Aufgabenlösung und da gibt's auch
andere Aspekte in Betracht zu ziehen.
Post by Michael Zimmermann
Du hast mich inzwischen davon überzeugt, Paul, daß fehlende
Klassengeneralisierung keine Frage des Gefallens oder
Nichtgefallens, sondern tatsächlich eine objektive
Fehlentwicklung ist.
Schön, dass du Objektivität beanspruchst.
Post by Michael Zimmermann
Dafür, daß jemand, wie Du es andeutest, ein Problem lösen
will, ohne dabei gleichzeitig eine möglichst allgemein
anwendbare Lösungsschablone zu entwerfen, ist in meinem
Weltbild jetzt definitiv kein Platz mehr.
Macht wohl auch nichts.
Post by Michael Zimmermann
Das ist zwar nicht in Deinem Sinne, aber danke für die
Gewißheit. ;-)
Solche Ergebnisse von Diskussionen und Gedanken sind wohl oft wichtiger
als das Ursprungsthema. :-)
Post by Michael Zimmermann
Post by Paul Rohorzka
Ich würde es schade finden, wenn diese Diskussion - so
oft sie auch schon geführt wurde - nicht auf sachlicher
Ebene weitergehen würde.
Sie darf gerne auch etwas polemisch sein. An Podendorfismen
habe ich aber keinen Bedarf.
Das sind wir uns ja wohl einig.

LG,
Paul
--
http://www.softconcept.at - Development, Solutions, Tools
http://access.primary.at - Wiener Access-Stammtisch
Jörg Ostendorp
2005-12-05 18:09:01 UTC
Permalink
Hallo Paul, Hallo Gottfried,
[ganz viel über Klassen]
Was mich mal interessieren würde, ist, ob ihr eigentlich "nur" Eure Daten
kapselt oder ob Ihr das auch mit /sämtlichen/ anderen Datenbankobjekten
macht? Gerade im Hinbllick auf das Argument sich ändernder
Feldbezeichnungen in Tabellen, SQL-Ungetümen, (Hard-)Coderedundanz und Co,
wäre das doch eigentlich nur konsequent. Schließlich kann sich ja auch mal
ein Formular oder Controlname ändern.

Viele Grüße
Jörg Ostendorp
Paul Rohorzka
2005-12-05 20:27:00 UTC
Permalink
Hallo Jörg!
Post by Jörg Ostendorp
[ganz viel über Klassen]
Was mich mal interessieren würde, ist, ob ihr eigentlich "nur" Eure Daten
kapselt oder ob Ihr das auch mit /sämtlichen/ anderen Datenbankobjekten
macht? ...
Wie schon in anderen Postings zum Ausdruck gebracht ist die Kapselung
für mich nur ein Vorteil der Verwendung von Klassen. Vieles davon hat ja
eigentlich nicht einmal besonders viel mit Objektorientierung im engeren
Sinn zu tun.

Ich kapsle also nicht der Kapselung willen, sondern ich setze dort
Klassen ein, wo es mir sinnvoll erscheint. Das ist zugegebener Maßen
ziemlich oft.
Post by Jörg Ostendorp
... Gerade im Hinbllick auf das Argument sich ändernder
Feldbezeichnungen in Tabellen, SQL-Ungetümen, (Hard-)Coderedundanz und Co,
wäre das doch eigentlich nur konsequent. Schließlich kann sich ja auch mal
ein Formular oder Controlname ändern.
Die Anwendung von Klassen hat für mich rein Gründe der Praktikabilität
bei der Software-Entwicklung. Wenn man das Konzept zu weit denkt und
damit beginnt um alles und jedes Trumm eine Kapselklasse zu schreiben
wird's pervers. Schließlich sind die drei großen Vorteile beim Einsatz
von Access für mich (a) die gebundenen Formulare, (b) die Berichte und
(c) das (oft mögliche) Verteilen per kopieren (noch bevor Microsoft im
Zusammenhang mit .NET das XCopy-Deployment propagiert hat). Wenn ich
anfange, überall meine eigenen Klassen reinzustopfen, verzichte ich auf
die/manche Vorteile von Access. Und ohne diese Vorteile gibt's leider
nicht viel Gründe, bei Access zu bleiben, denn die anderen Dinge aus
denen Softwareentwicklung besteht können andere Entwicklungsumgebungen
und Systeme meist besser (z.B. richtiges OO mit Implementierungsvererbung).

LG,
Paul
--
http://www.softconcept.at - Development, Solutions, Tools
http://access.primary.at - Wiener Access-Stammtisch
Gottfried Lesigang
2005-12-06 23:01:56 UTC
Permalink
Grüß dich Jörg!
Post by Jörg Ostendorp
[ganz viel über Klassen]
Was mich mal interessieren würde, ist, ob ihr eigentlich "nur" Eure Daten
kapselt oder ob Ihr das auch mit /sämtlichen/ anderen Datenbankobjekten
macht?
Zu jeder Tabelle zwei Klassen: Eine Element- und eine Listenklasse. Ich gehe
da in der Namensgebung ganz streng ran, wodurch sich ganz viel mit
"Copy'n'Paste" und dann mit "Replace" anpassen lässt. Die Tabelle heißt z.B.
tblPerson. Die Elementklasse heißt dann clsPerson und die Liste heißt
clsPersonList. Der PrimaryKey ist stets vom Typ Long und heißt PersonID, ein
zugeordnetes Formular heißt dann frmPerson usw.

Die Klassen haben
Private Const pcMyTableName As String = "tblXyz"
Private Const pcMyPrimaryKey As String = "XyzID"

Im Zugriff verwende ich dann diese Konstanten, also etwa

"SELECT * FROM " & pcMyTableName & " WHERE " & pcMyPrimaryKey & "=" & mXyzID

Sollte sich wirklich mal z.B. ein Tabellenname ändern, genügt es die
Konstante anzupassen.

In der "Create...ByDAORs()" (s. dazu Posting an Michael) werden die
Feld-Werte des aktuellen Records in die privaten Variablen geschrieben. Dort
und *nur* dort stehen die Feldnamen. Eine Anpassung ist also sehr einfach.

Das - und noch ein paar Klasse dazu - sind für mich die "Buisness-Schicht".
Als Datenschicht könnte man jetzt allgemeine Klassen a la
"Entity("Kunde").Value("Vorname") (s. Michael) verwenden. Da begnüge ich
mich mit DAO.

Ich habe gerade in einem Posting an Michael sehr ausführlich einiges dazu
dargestellt, das möchte ich jetzt nicht nochmals hier anführen. Bitte dort
nachlesen...
Post by Jörg Ostendorp
Gerade im Hinbllick auf das Argument sich ändernder
Feldbezeichnungen in Tabellen, SQL-Ungetümen, (Hard-)Coderedundanz und Co,
wäre das doch eigentlich nur konsequent. Schließlich kann sich ja auch mal
ein Formular oder Controlname ändern.
Die Präsentations-Schicht ist da - besonders bei Access! - was anderes. Denn
man müsste auf die vielen Automatismen, die vielen Helferleins verzichten,
die das gebundene Arbeiten mit sich bringt. Wie gerade an Michael gepostet
habe ich mal ein Projekt so umgesetzt. Das war aber sehr aufwändig!

Zurzeit benutze ich die Objekte vor allem dort, wo es 1) um einen einfachen
und sicheren Zugriff oder 2) um Objekt-gebundene Logik geht.

lg
Gottfried
Paul Rohorzka
2006-01-16 14:44:47 UTC
Permalink
Hallo Jörg,

trotz langer Abstinenz von diesem Thread noch ein paar Sätze.
Post by Jörg Ostendorp
Hallo Paul, Hallo Gottfried,
[ganz viel über Klassen]
Was mich mal interessieren würde, ist, ob ihr eigentlich "nur" Eure Daten
kapselt oder ob Ihr das auch mit /sämtlichen/ anderen Datenbankobjekten
macht?
Ich muss vielleicht ein Bild korrigieren. Ich kapsle in meinen
Access-Anwendungen beileibe nicht alle Daten. Das ist mir zum einen viel
zu mühsam (besonders in Zeiten, bevor Thomas Möller seinen wunderbaren
Datenkapselklassengenerator entwickelt hat) und zum anderen im Kontext
der datengebundenen Steuerelementen von Access nicht überall
praktikabel. Diese Klassen verwende ich nur dort, wo ich per VBA-Code
Zugriff auf die Daten benötige. Und manchmal verwende ich trotzdem sogar
ein einfaches Lookup, weil's so wunderbar bequem ist.
Post by Jörg Ostendorp
Gerade im Hinbllick auf das Argument sich ändernder
Feldbezeichnungen in Tabellen, SQL-Ungetümen, (Hard-)Coderedundanz und Co,
wäre das doch eigentlich nur konsequent. Schließlich kann sich ja auch mal
ein Formular oder Controlname ändern.
Stimmt zwar, aber vor Fehlern im Datenzugriff habe ich wesentlich mehr
Respekt, als vor falschen Steuerelementnamen. Hinzu kommt, dass ich
trotz aller Unkenrufe konsequent Me.Steuerelement statt Me!Steuerelement
verwende, weshalb der Compiler schon schreit, wenn ein Feldname nicht
stimmt. Bei falschen Feldnamen geht das halt nur, wenn man eine
entsprechende Datenkapselklasse hat.

LG,
Paul
--
http://www.softconcept.at - Development, Solutions, Tools
http://access.primary.at - Wiener Access-Stammtisch
Jörg Ostendorp
2005-12-01 16:34:47 UTC
Permalink
Hallo Michael,
Post by Michael Zimmermann
Generell solltest Du Dir von Klassen keine Wunderdinge
erwarten. Du kannst damit dasselbe machen wie in
Standardprozeduren, nur daß die wiederholte Verwendung
weitaus anschaulicher ist.
Grummel... Also Raise Event und WithEvents fallen bei mir
durchaus schon in die Kategorie 'Wunderdinge'.

Viele Grüße
Jörg Ostendorp
Michael Zimmermann
2005-12-01 17:04:06 UTC
Permalink
Hallo!
Post by Jörg Ostendorp
Grummel... Also Raise Event und WithEvents fallen bei mir
durchaus schon in die Kategorie 'Wunderdinge'.
Du bist leicht zu beeindrucken.

Wundern tue ich mich erst, wenn eine Prophecy-Klasse
einfach so weiß, was jetzt gerade am trefflichsten zu
tun sei. ;-)

Gruß aus Mainz
Michael
Ka Prucha
2005-12-01 17:35:05 UTC
Permalink
"Michael Zimmermann" schrieb
Post by Michael Zimmermann
Wundern tue ich mich erst, wenn eine Prophecy-Klasse
einfach so weiß, was jetzt gerade am trefflichsten zu
tun sei. ;-)
<petzmodus>

Das sag ich Paul!

</petzmodus>

mfg Ka Prucha
--
.... möglichst komplett und als Textfile.
Bislange habe ich nur eine Datenbankversion, die für eine schnelle Suche
nicht wirklich taugt.
Matthias Arndt in de.comp.sys.atari
Jörg Ostendorp
2005-12-01 17:50:27 UTC
Permalink
Hallo Micheal,
Post by Michael Zimmermann
Wundern tue ich mich erst, wenn eine Prophecy-Klasse
einfach so weiß, was jetzt gerade am trefflichsten zu
tun sei. ;-)
Ah, Du meinst sowas wie Karl Klammer? ;-)


Viele Grüße
Jörg Ostendorp
Michael Zimmermann
2005-12-01 18:08:52 UTC
Permalink
Hallo!
Post by Jörg Ostendorp
Post by Michael Zimmermann
Wundern tue ich mich erst, wenn eine Prophecy-Klasse
einfach so weiß, was jetzt gerade am trefflichsten zu
tun sei. ;-)
Ah, Du meinst sowas wie Karl Klammer? ;-)
Nein, den Magic Eight Ball, falls den noch jemand kennt.
;-)

Gruß aus Mainz
Michael
Mark Doerbandt
2005-12-01 18:43:08 UTC
Permalink
Hallo, Michael,
Post by Michael Zimmermann
Nein, den Magic Eight Ball, falls den noch jemand kennt.
;-)
... den da:

http://www.mogelpower.de/easter/eggs/egg.php?id=5

? Wie kommt das nur, dass Dir dumme Sprueche gefallen?

;-) Gruss - Mark
--
Informationen fuer Neulinge in den Access-Newsgroups unter
http://www.doerbandt.de/Access/Newbie.htm

Bitte keine eMails auf Newsgroup-Beiträge senden.
Jörg Ostendorp
2005-12-01 21:38:15 UTC
Permalink
Hallo Michael,
Post by Michael Zimmermann
Post by Jörg Ostendorp
Post by Michael Zimmermann
Wundern tue ich mich erst, wenn eine Prophecy-Klasse
einfach so weiß, was jetzt gerade am trefflichsten zu
tun sei. ;-)
Ah, Du meinst sowas wie Karl Klammer? ;-)
Nein, den Magic Eight Ball, falls den noch jemand kennt.
;-)
Ich nicht. Glaube, den kennen höchstens die Uralt-Gruftis, die noch mit
A<=97 groß geworden sind.
SCNR ;-)

Viele Grüße
Jörg Ostendorp
Paul Rohorzka
2005-12-03 12:59:05 UTC
Permalink
Hallo Michael!
Post by Michael Zimmermann
Post by Bodo Greiner
bei (schon früher erwähnter) leicht chaotischer
Anwendung, die ich übernommen habe, ...
"Entwicklerhandschrift." ;-)
Sauhaufen. ;-)
Post by Michael Zimmermann
Post by Bodo Greiner
...
Meine Frage: Wenn ich das also neu programmiere, sollte
ich es dann (relativ) objektorientiert tun mit
Klassenmodulen? Einige Grundlagen von Klassenmodulen und
Vorzüge davon kenne ich; allerdings weiß ich nicht, wie's
aussieht mit dem Aufwand für diverse Berechnungen, die
dann auch programmiert werden müssen auf diese (relativ)
objektorientierte Weise.
Spart man dabei Arbeit?
Nur wenn Du den Code immer wieder verwendest.
Nun ja, die hier angesprochene Wiederverwendbarkeit ist IMHO nur ein
Aspekt bei Programmierung unter Verwendung von Klassen (siehe meine
Antwort auf das OP).
Post by Michael Zimmermann
Eine Funktion, die in einer großen Schleife Werte addiert,
sollte man nicht in eine Klasse einpacken, schon gar, wenn
diese Funktion nur einmal gebraucht wird. Durch die Wrapper-Klasse
wird's nur unnötig verlangsamt.
Genau - stattdessen natürlich auch die Schleife in die Klasse aufnehmen!
Das meine ich ernst (kein Smiley).
Post by Michael Zimmermann
Funktionalitäten, die man anschaulich als Objekt sehen kann,
z. B. ein File-Dialog, eine Textdatei, einen Ordner, eine
Hierarchie, und die man immer wieder benutzt, sind in einer
Klasse besser aufgehoben.
Auch wenn ich sie nur einmal brauche, kapselt die Klasse sauberer und
macht die /Verwendung/ der Funktionalität einfacher und sicherer.
Post by Michael Zimmermann
Ich selbst benutze aus prinzipiellen Erwägungen nur
generische Klassen, die sich auf Objekte der Datenbank-
Meta-Ebene beziehen, nie Klassen für konkrete Inhalte.
Wenn du mit "konkreten Inhalten" konkrete Datensätze meinst, ist das ja
wohl klar.
Post by Michael Zimmermann
Also z. B. keine "Kundenklasse" o. ä. Die (sinnvolle)
generische Klasse, die das gleichartige Behandeln
beliebiger Datenzusammenstellungen erlaubt, gibt es
schon, die heißt Recordset.
Aha! Aber das Recordset ist mir oft zu generisch. /Ich will/ eine
Kundenklasse, weil ich mich nicht mit meinen Feldnamen und sonstigem
Quiqui jedesmal neu beschäftigen will. Ich will Features implementieren! ;-)
Post by Michael Zimmermann
Aber z. B. eine Stack- und eine Queue-Klasse, weil das
allgemeine Objekte sind, die man immer und überall braucht.
Klar, da sowieso (aber auch nur, weil uns die Standard-Bibliotheken von
VB Classic uns hier unverständlicherweise im Stich lassen).
Post by Michael Zimmermann
Post by Bodo Greiner
Oder fällt man auf die Schnauze,
wenn man sich nicht "perfekt" mit dieser Technik
auskennt?
Naa. Falls Du nicht gerade in komplexen Objektmodellen
Zirkelbezüge fabrizierst, ist Klassenprogrammierung
recht robust und nicht sonderlich schwierig.
Robust: ja, nicht sonderlich schwierig: naja. So schnell einmal
eingestiegen ist man rasch, aber dass das Ganze auch rund und sinnvoll
anzuwenden ist, erfordert einiges an Erfahrung. Ich traue mich zwar zu
sagen, dass ich schon einige Klassen geschrieben habe, aber immer wieder
gibt es Situationen, in denen sich mir neue Fragen oder Probleme stellen.
Post by Michael Zimmermann
Post by Bodo Greiner
Das Thema Klassen wird in Lehrbüchern zu Äccess
allgemein stiefmütterlich behandelt
Generell solltest Du Dir von Klassen keine Wunderdinge
erwarten.
Genau! Aber kuhl sind's schon! Hihi! Rufezeichen.
Post by Michael Zimmermann
Du kannst damit dasselbe machen wie in
Standardprozeduren, nur daß die wiederholte Verwendung
weitaus anschaulicher ist.
Also aus Sicht des Entwicklers stimmt das nicht, da kann man sehr wohl
mit Klassen Dinge tun, die ohne nicht gehen. Aus Sicht des Anwenders
hast du natürlich recht. Wie wir aber wissen, interessiert dich der ja
nur als /noch nicht/ wegzunormalisierendes Übel. ;-)

LG aus Wien,
Paul
--
http://www.softconcept.at - Development, Solutions, Tools
http://access.primary.at - Wiener Access-Stammtisch
Michael Zimmermann
2005-12-03 17:32:15 UTC
Permalink
Hallo!
Post by Paul Rohorzka
Post by Michael Zimmermann
"Entwicklerhandschrift." ;-)
Sauhaufen. ;-)
Genau! ;-)
Post by Paul Rohorzka
Post by Michael Zimmermann
Nur wenn Du den Code immer wieder verwendest.
Nun ja, die hier angesprochene Wiederverwendbarkeit ist
IMHO nur ein Aspekt bei Programmierung unter Verwendung
von Klassen ...
Ja. Allerdings einer der wichtigeren. Um Funktionalitäten
nur ja nicht doppelt implementieren zu müssen, hat man
sich doch die Vererbung in erster Linie ausgedacht, wenn
ich mich recht entsinne.
Post by Paul Rohorzka
Genau - stattdessen natürlich auch die Schleife in die
Klasse aufnehmen! Das meine ich ernst (kein Smiley).
Zum Beipiel. Ich habe aber schon genug Exempel gesehen,
wo einer aus lauter Klassenfreude primitive Funktionen
in eine Klasse gekapselt hat, um das dann in einem
Standard(!)modul in einer Schleife aufzurufen.
Post by Paul Rohorzka
Post by Michael Zimmermann
Funktionalitäten, die man anschaulich als Objekt sehen
kann, z. B. ein File-Dialog, eine Textdatei, einen
Ordner,
eine Hierarchie, und die man immer wieder benutzt, sind
in einer Klasse besser aufgehoben.
Auch wenn ich sie nur einmal brauche, kapselt die Klasse
sauberer und macht die /Verwendung/ der Funktionalität
einfacher und
sicherer.
Das ist richtig. Es geht auch mehr darum, daß man sie
mehrfach brauchen /kann/. Etwas, das seinem Status nach
als Instanz anzusehen ist, in eine eigene Klasse zu packen,
halte ich für falsch.
Post by Paul Rohorzka
Post by Michael Zimmermann
Also z. B. keine "Kundenklasse" o. ä. Die (sinnvolle)
generische Klasse, die das gleichartige Behandeln
beliebiger Datenzusammenstellungen erlaubt, gibt es
schon, die heißt Recordset.
Aha! Aber das Recordset ist mir oft zu generisch. /Ich
will/ eine Kundenklasse, weil ich mich nicht mit meinen
Feldnamen und sonstigem Quiqui jedesmal neu beschäftigen
will. Ich will Features implementieren! ;-)
Kunden sind nicht generisch genug, da es sie nicht immer
gibt.

Was ist an
Dingsbums("Kunde").Eigenschaft
oder
Dingsbums1.Typ = "Kunde"
Dingsbums2.Typ = "Lieferant"
?Dingsbums1.Properties("Adresse")
?Dingsbums2.Properties("Lieferfrist")
schlimmer als an
Kunde.Adresse
Lieferant.Lieferfrist

außer daß man es in jeder DB benutzen kann?
Post by Paul Rohorzka
Post by Michael Zimmermann
Naa. Falls Du nicht gerade in komplexen Objektmodellen
Zirkelbezüge fabrizierst, ist Klassenprogrammierung
recht robust und nicht sonderlich schwierig.
Robust: ja, nicht sonderlich schwierig: naja. So schnell
einmal eingestiegen ist man rasch, aber dass das Ganze
auch rund und sinnvoll anzuwenden ist, erfordert einiges
an Erfahrung. Ich traue mich zwar zu sagen, dass ich
schon einige Klassen geschrieben habe, aber immer wieder
gibt es Situationen, in denen sich mir neue Fragen oder
Probleme stellen.
Das ist aber normal. Man lernt nie aus. Es ist aber auch
schon mancher aus falschem Respekt vor den Klassen vom
Einstieg abgehalten worden. Das kannst Du doch nicht
wollen? ;-)
Post by Paul Rohorzka
Post by Michael Zimmermann
Du kannst damit dasselbe machen wie in
Standardprozeduren, nur daß die wiederholte Verwendung
weitaus anschaulicher ist.
Also aus Sicht des Entwicklers stimmt das nicht, da kann
man sehr wohl mit Klassen Dinge tun, die ohne nicht gehen.
Ein Berechenbarkeitsproblem, das auschließlich
objektorientiert implementierbar ist und sich einer rein
prozeduralen Lösung verschließt, obwohl die prozedurale
Sprache turing-vollständig ist? Was sollte das sein?
Post by Paul Rohorzka
Aus Sicht des Anwenders hast du natürlich recht. Wie wir
aber wissen, interessiert dich der ja nur als /noch
nicht/ wegzunormalisierendes Übel. ;-)
Aber nein, solange er tut, was er soll, finde ich ihn
entzückend. ;-)

Gruß aus Mainz
Michael, ich hab doch nix gegen Klassen
Gottfried Lesigang
2005-12-03 19:24:02 UTC
Permalink
Hallo!
Post by Michael Zimmermann
Ja. Allerdings einer der wichtigeren. Um Funktionalitäten
nur ja nicht doppelt implementieren zu müssen, hat man
sich doch die Vererbung in erster Linie ausgedacht, wenn
ich mich recht entsinne.
Du argumentierst da zu negativ. IMO ging es vor allem um eine möglichst
zutreffende Abbildung der realen Welt. Und da macht es nunmal Sinn, von
einer allgemeinen Begriff wie "Obst" konkretere wie "Apfel" und "Birne"
abzuleiten.
Post by Michael Zimmermann
Zum Beipiel. Ich habe aber schon genug Exempel gesehen,
wo einer aus lauter Klassenfreude primitive Funktionen
in eine Klasse gekapselt hat, um das dann in einem
Standard(!)modul in einer Schleife aufzurufen.
Und du sagst sinngemäß, dass die Verwendung von Klassen einfach und
eigentlich recht robust sei ;-)

Das ist es ja gerade! Die Schwierigkeit liegt im Design...
Post by Michael Zimmermann
Das ist richtig. Es geht auch mehr darum, daß man sie
mehrfach brauchen /kann/. Etwas, das seinem Status nach
als Instanz anzusehen ist, in eine eigene Klasse zu packen,
halte ich für falsch.
Und ich halte genau das für einen Paradefall von OOP. Unterschiedliche
Instanzen stellen durch die Kapselung ihrer Zustände konkrete Objekte dar.
Das ist doch gerade OOP!
Post by Michael Zimmermann
Dingsbums("Kunde").Eigenschaft
oder
Dingsbums1.Typ = "Kunde"
Dingsbums2.Typ = "Lieferant"
?Dingsbums1.Properties("Adresse")
?Dingsbums2.Properties("Lieferfrist")
schlimmer als an
Kunde.Adresse
Lieferant.Lieferfrist
Meinst du das wirklich so wie es da steht?
Post by Michael Zimmermann
Ein Berechenbarkeitsproblem, das auschließlich
objektorientiert implementierbar ist und sich einer rein prozeduralen
Lösung verschließt, obwohl die prozedurale
Sprache turing-vollständig ist? Was sollte das sein?
Es hat doch niemand gesagt, dass irgendetwas, das mit OOP lösbar ist,
prozedural *nicht* geht!? So gesehen kann man aber auch auf Prozeduren
verzichten! Es geht doch auch alles in Maschinensprache...
Post by Michael Zimmermann
Michael, ich hab doch nix gegen Klassen
Und ich dachte schon du seist der Klassenfeind ;-)

lg
Gottfried
Jens Schilling
2005-12-01 11:59:34 UTC
Permalink
Hallo, Bodo
Post by Bodo Greiner
Woher (Bücher? Kollegen? Internet? MSDN?) bekommen denn
Access-Programmierer ihr /detailliertes/ Know-how zu Klassenmodulen?
Nun, z.B. durch die Teilnahme an der AEK ;-)

Du kannst im Downloadbereich zur 7. und 8. AEK jeweils einen Vortrag von
Paul Rohorzka zum Thema finden.
--
Gruss
Jens
______________________________
FAQ: http://www.donkarl.com
Bodo Greiner
2005-12-01 12:03:57 UTC
Permalink
Hallo Jens!
Post by Jens Schilling
Hallo, Bodo
Post by Bodo Greiner
Woher (Bücher? Kollegen? Internet? MSDN?) bekommen denn
Access-Programmierer ihr /detailliertes/ Know-how zu Klassenmodulen?
Nun, z.B. durch die Teilnahme an der AEK ;-)
Du kannst im Downloadbereich zur 7. und 8. AEK jeweils einen Vortrag von
Paul Rohorzka zum Thema finden.
Super! Danke! Wenn ich zur nächsten AEK komme (wann ist die?), dann kannst
Du die Provision dafür einstreichen (falls es eine gibt).

Gruß, Bodo
Jens Schilling
2005-12-01 12:37:09 UTC
Permalink
Hallo, Bodo
Post by Bodo Greiner
Post by Jens Schilling
Nun, z.B. durch die Teilnahme an der AEK ;-)
Du kannst im Downloadbereich zur 7. und 8. AEK jeweils einen Vortrag
von Paul Rohorzka zum Thema finden.
Super! Danke! Wenn ich zur nächsten AEK komme (wann ist die?),
Im allgemeinen Anfang/Mitte Oktober - in diesem Jahr gab's erstmalig zwei
Termine zur Auswahl.
Post by Bodo Greiner
kannst Du die Provision dafür einstreichen (falls es eine gibt).
;-)
--
Gruss
Jens
______________________________
FAQ: http://www.donkarl.com
Karl Donaubauer
2005-12-01 12:41:56 UTC
Permalink
Hallo, Jens!
Post by Jens Schilling
Post by Bodo Greiner
Post by Jens Schilling
Nun, z.B. durch die Teilnahme an der AEK ;-)
Du kannst im Downloadbereich zur 7. und 8. AEK jeweils einen Vortrag
von Paul Rohorzka zum Thema finden.
Super! Danke! Wenn ich zur nächsten AEK komme (wann ist die?),
Im allgemeinen Anfang/Mitte Oktober - in diesem Jahr gab's erstmalig
zwei Termine zur Auswahl.
Zitat von www.donkarl.com/aek:
*****
Die nächste AEK wird Anfang Oktober 2006 am gleichen Ort und
mit gleichem Modus stattfinden.
*****
Post by Jens Schilling
Post by Bodo Greiner
kannst Du die Provision dafür einstreichen (falls es eine gibt).
;-)
Ok, 1 Cocktail, der diesmal vielleicht sogar brennt und damit den
Barlehrling glücklicher macht.
--
cu
Karl
********* Ich beantworte keine Access-Fragen per Email. *********
Access-FAQ: http://www.donkarl.com
Datenbank-Profis: http://www.dbdev.org
Jens Schilling
2005-12-01 13:20:02 UTC
Permalink
Hallo, Karl
Post by Karl Donaubauer
Post by Bodo Greiner
Super! Danke! Wenn ich zur nächsten AEK komme (wann ist die?),
kannst Du die Provision dafür einstreichen (falls es eine gibt).
;-)
Ok, 1 Cocktail, der diesmal vielleicht sogar brennt und damit den
Barlehrling glücklicher macht.
Der war gut der Junge, nicht wahr ;-)
Und da er 2006 ja schon ein Lehrjahr weiter ist, dürfen wir dann vielleicht
sogar einen echten Feuerzauber erleben ;-)
--
Gruss
Jens
______________________________
FAQ: http://www.donkarl.com
Ka Prucha
2005-12-01 16:38:35 UTC
Permalink
"Bodo Greiner" schrieb
Post by Bodo Greiner
Beispiel: Bereits in einer Form_Load Prozedur
eines Formulars, in dem Bestellungen bearbeitet werden, werden alle
möglichen Werte in zugrundeliegende Tabellen (die nicht verknüpft sind :-))
reingeschrieben und obendrein im Modul dieses Formulars als modulweit
deklarierte Variablen gespeichert. Für den Fall, daß die Bestellung
abgebrochen wird, werden die bereits eingetragenen Werte aus den Tabellen
wieder rausgelöscht.
Servus

Warum für diesen Fall nicht einfach eine Transaktion verwenden?
Das Ganze wird dabei automatisch im lokalen Temporär Ordner
vollzogen und erst beim commit in die Datenbank geschrieben.
Im anderen Fall löscht rollback einfach die Temporärdateien ohne
das sich irgend etwas in der DB verändert hätte.

Funktioniert übrigens auch bei nicht verknüpften Tabellen.
(In meinem Fall Kopien von Veränderungen in "History" Tabellen.)

mfg Ka Prucha
Paul Rohorzka
2005-12-03 12:48:22 UTC
Permalink
Hallo Bodo!
Post by Bodo Greiner
bei (schon früher erwähnter) leicht chaotischer Anwendung, die ich
übernommen habe, [...]
Meine Frage: Wenn ich das also neu programmiere, sollte ich es dann
(relativ) objektorientiert tun mit Klassenmodulen? Einige Grundlagen von
Klassenmodulen und Vorzüge davon kenne ich; allerdings weiß ich nicht, wie's
aussieht mit dem Aufwand für diverse Berechnungen, die dann auch
programmiert werden müssen auf diese (relativ) objektorientierte Weise.
Wenn du mit dem Thema noch keine relevante praktische Erfahrung
gesammelt hast, würde ich dir bei einem solchen Unterfangen davon
abraten, alles auf Klassen umstellen zu wollen. Eher empfehle ich einen
schrittweisen Umstieg, dort wo dir die Vorteile offensichtlich sind.
Post by Bodo Greiner
Spart man dabei Arbeit? Oder fällt man auf die Schnauze, wenn man sich nicht
"perfekt" mit dieser Technik auskennt?
IMHO: ja. Perfekt musst du nicht sein, aber doch recht genau wissen, was
du tust.
Post by Bodo Greiner
Das Thema Klassen wird in Lehrbüchern
zu Äccess allgemein stiefmütterlich behandelt (Ausnahme: "Das Access 2003
Entwicklerbuch" von André Minhorst, durch das ich überhaupt auf die Idee
komme mir zu überlegen, ob ich mit Klassen arbeiten will).
Obwohl ich das genannte Buch nicht kenne, kann ich dir zustimmen. Die
Klassenbeispiele in den div. Access-Büchern sind IMHO nur der
Vollständigkeit halber da (außer vielleicht im ADH, da gibt's gute
Beispiele). Besonders Datenkapselklassen werden nicht relevant beschrieben.
Post by Bodo Greiner
Woher (Bücher? Kollegen? Internet? MSDN?) bekommen denn Access-Programmierer
ihr /detailliertes/ Know-how zu Klassenmodulen?
Neben allen Hinweisen, die du schon bekommen hast, kann ich dir auch das
Buch "Visual Basic 6 Business Objects" von Rockford Lhotka empfehlen.
Das Buch ist zwar schon etwas angegraut, aber das Codieren in Access ist
ja immer noch auf VB6-Basis, so gesehen passt meist ganz gut, was er
schreibt (außer wenn's in die ActiveX-Server/DCOM-Ecke geht).



Da ich mit der Thematik auch in Access mittlerweile schon einige
Erfahrung gesammelt habe, möchte ich Vor- und Nachteile aus meiner Sicht
darlegen (es ist ein ziemlich langer Text geworden, gute Nerven beim
Lesen!):

Nachteile
=========

*N1) Klassen zu schreiben ist weder trivial noch schnell erledigt*
Klassen müssen bevor sie verwendet werden können erst einmal geschrieben
werden. Das erfordert zum einen KnowHow, Vorausplanung und Zeit. Das
Coden der Klasse an sich mag nicht viel Unterschied zum Coden eines
Standardmoduls sein. Die Praktikabilität einer Klasse oder gar einer
Struktur von Klassen steht und fällt aber mit einem sinnvollen Design.
Dazu sind wiederum einiges an Wissen, Erfahrung und Gefühl vonnöten.
Gerade das Implementieren von Eigenschaftsprozeduren erfordert einigen
knechtischen Codierungsaufwand. Hier empfiehlt sich die Zuhilfenahme von
Tools (Mz-Tools, Die Assistenten von Thomas Möller (Datenklassen) und
Dev Ashish & Terry Kreft, VB6 (Klassensassisten), etc.). Diese Tools
haben alle ihre Vor- und Nachteile (weil unterschiedliche
Stoßrichtungen), ersparen aber viel Tipparbeit. Dennoch bleibt immer
sehr viel selbst zu tun.


*N2) Code in Klassen ist oft komplizierter aufzurufen* (mit mehr
syntaktischem Geplänkel).

Dim objCalculator As CCalculator

Set objCalculator As New CCalculator
Out = objCalculator.Calc(In) ' Aufruf einer Methode einer Klasse
Set objCalculator = Nothing

statt

Out = Calc(In) ' Aufruf einer Methode eines Standardmoduls

Bemerkungen:
- Für solche Dinge ist es natürlich sehr fragwürdig, überhaupt ein
Klasse zu verwenden, kann aber ev. doch auch Sinn machen - siehe unten.
- Für solche Anwendungen besteht in gscheiten OO-Sprachen die
Möglichkeit statische Methoden (oder in VB.NET "Shared") anzulegen.
Damit könnte man direkt in obigem Beispiel folgendes schreiben:

Out = CCalculator.Calc(In)

Is aber leider nicht in VB(A)6.


Vorteile
========

*V1) Einschränkung der Sichtbarkeit*
Elemente von Klassen sind ohne Angabe eines Instanznamens nicht
sichtbar. Das halte ich für einen großen Vorteil, da klarer wird, welche
Methode oder Eigenschaft woher kommt und die Zusammenhänge klarer macht,
als viele öffentliche Methoden aus Standardmodulen.


*V2) Verwendung von Enums*
Auzählungstypen (Enums) sind eine hübsche Möglichkeit, nummerische
Konstanten zu logischen Gruppen zusammenzufassen. Durch die
Unterstützung seitens Intellisense kann Code damit lesbarer gestaltet
werden.


*V3) Reagieren auf Ereignisse (WithEvents)*
Nur in Klassenmodulen kann unter Zuhilfenahme des Schlüsselwortes
WithEvents auf Ereignisse reagiert werden, die von Objekten (Formularen,
Steuerelementen, Instanzen eigener Klassen, etc.) ausgelöst werden.
Damit kann bspws. im Code einer einzigen Klasse auf die Ereignisse
beliebig vieler Formulare und deren Steuerelementen reagiert werden um
damit Standardverhalten zu implementieren (siehe Gottfrieds
FormBehaviour-Klasse). Erweiterungen, Änderungen und Bugfixes sind nur
mehr an einer einzigen Stelle nötig, Duplizierung von Code wird vermieden.

Beispiel:
Ein grafischer Sitzplan für ein Theater, bei dem jeder Sitzplatz als
Bezeichnungsfeld dargestellt wird, und auf Klicks, etc. entsprechend
reagiert werden muss. Hier müsste eigentlich für jedes Bezeichnungsfeld
(einige hundert) im Formular die Click-Ereignisroutine implementiert
werden, zumindest müsste eine Methode aufgerufen werden. Wenn
stattdessen pro Bezeichnungsfeld eine Instanz der Klasse CSitzplatz auf
die Ereignisse seines Bezeichnungsfeldes reagiert, muss dieser Code nur
mehr an einer einzigen Stelle implementiert werden. Die Instanziierung
von CSitplatz und die Zuordnung zwischen den beiden Objekten kann aber
in Form_Open in einer Schleife erfolgen.


*V4) Definieren und auslösen von Ereignissen (Event, RaiseEvent)*
Nur in Klassenmodulen lassen sich eigene Ereignisse definieren
(Schlüsselwort Event) und auch auslösen (Anweisung RaiseEvent). Damit
hat ein Objekt die Möglichkeit, ev. sehr geschwätzig über
Zustandswechsel und ähnliches zu informieren, ohne auch nur irgendwelche
Annahmen über den oder die Empfänger dieser "Nachrichten" zu treffen.
Wenn anderer Code an dem einen oder anderen Ereignis interessiert ist,
"abonniert" er es, wenn nicht, lässt er es einfach links liegen. Ein
weiterer Aspekt ist, dass das auslösende Objekt keine Ahnung davon haben
muss, ob überhaupt und falls wie viele Abonennten auf seine Ereignisse
reagieren.

Bemerkungen:
- Was hier stattdessen gerne gemacht wird, ist, beim zu
benachrichtigenden Objekt eine Voraussetzung über das Vorhandensein
einer bestimmten Methode mit einer bestimmten Signatur zu treffen. Es
wird dann versucht (mit entsprechendem Fehlerhandling), diese
aufzurufen. Diese Vorgangsweise koppelt Sender und Empfänger sehr stark
aneinander. Eine größere Anzahl von Abonennten ist damit auch nicht
(einfach, mit etwas Aufwand schon) zu realisieren.
- Die Möglichkeit, eigene Ereignisse auslösen zu können, ist für mich
ein sehr wichtiger Grund, warum ich selbst typischen Standardmodul-Code
(wie z.B. Berechnungen über den Datenbestand) in eine Klassenmodul
auszulagere. Damit kann ein eventuell länger laufendes Codestück seine
Umgebung über den Fortschritt des Ablaufs informieren. Weiters kann hier
wunderbar ein Abbruch-Mechanismus eingebaut werden (das geht aber auch
ohne Klasse). Die eigentliche Funktionalität ist damit komplett von
einer eventuellen GUI getrennt. Ich verwende das z.B. beim Generieren
von vielseitigen Worddokumenten (kann einige Minuten dauern), beim
Upload per FTP (kann ... dauern ;-)). Als Beispiel habe ich vor einigen
Wochen das Beispiel LongTaker ins Netz gestellt
(http://www.softconcept.at/softconcept/downloads/samples/LongTaker.zip).


*V5) Bessere Lesbarkeit von Quellcode*
Oft werden für einen Vorgang, eine Berechnung, uä. mehrere Parameter
benötigt. Wenn diese Parameter in Form einer längeren Parameterliste an
eine Methode übergeben werden, ist ohne Zuhilfenahme von Intellisense
die Bedeutung der einzelnen Parameter oft nicht klar. Hier kann das
Einstellen von Eigenschaftswerten eines Objekts und dann das Aufrufen
einer Methode klarer sein.

With myFTP
.Address = "ftp://meineseite.com"
.UserName = "ich"
.Password = "***@im"
.RemoteDir = "downloads"
.LocalDir = "\\data\public\internet\website\common"
.FileFilter = "*.zip"

.PutFiles

lngBytesTransmitted = .BytesTransmitted
End With

statt

lngBytesTransmitted = FtpPutFiles( _
"ftp://meineseite.com", _
"ich", _
"***@im", _
"downloads", _
"\\data\public\internet\website\common", _
"*.zip")

Bemerkung:
- Das ist auch ein Beispiel, wie der Code bei der Verwendung von Klassen
oft geschwätziger wird. Das halte ich aber für einen Vorteil, zumal wir
viele Teile des Codetextes nicht selbst tippen müssen
(Autovervollständigen).


*V6) Bereitstellen von Standardwerten - Vermeidung von optionalen
Parametern*
Wenn für eine Funktionalität manche Informationen angegeben werden
können, aber nicht unbedingt notwendig sind, können dafür optionale
Parameter eingesetzt werden. Optionale Parameter sind aber etwas
gefährlich, da es hier oft schwieriger ist, den richtigen Aufruf
sicherzustellen. Wenn stattdessen Eigenschaften verwendet werden, um die
gwünschten Daten bereitzustellen, lassen sich hier auch selten benötigte
Features anbieten ohne den Methodenaufruf zu verkomplizieren.

Bemerkungen:
- Optionale Parameter kommen manchmal wohl auch dort zum Einsatz, wo
nachträglich Features eingebaut werden müssen, der bestehnde Code aber
nicht verändert werden soll. Diese Vorgangsweise halte ich aus eigener
Erfahrung für nicht ganz ungefährlich, siehe oben.
- Besonders im Zusammenhang mit GUI interessant: Bei Objekten lassen
sich Standardwerte auch abfragen (und z.B. anzeigen), was bei optionalen
Parametern nicht möglich ist.
- Bei optionalen Parametern (OpenForm, etc.) bin ich gerade dabei, mir
die Verwendung benannter Argumente anzugewöhnen. Das mag ich zwar sonst
nicht, finde ich in diesem Fall aber sicherer.


*V7) Typisierter Datenzugriff*
Mit Hilfe von Datenkapselklassen lässt sich der Zugriff auf die Daten
einer Anwendung wunderbar unabhängig von den exakten Gegebenheiten
(Tabellen- und Feldnamen) der Datenstruktur machen. Durch die
Unterstützung von Intellisense wird der Zugriff auf die Daten der
Anwendung wesentlich vereinfacht.
Außerdem kann auf die Verwendung von Variants komplett verzichtet
werden, wodurch bereits der Compiler Möglichkeit bekommt, manche Fehler
schon vor dem Auftreten aufzudecken.
Gottfried hat in einem seiner Postings schon einige Beispiele geliefert.
Von mir im Sinne vorgenannter Beispiele und der Vollständigkeit halber
eine Gegenüberstellung (jeweils etwas Code weggelassen):

Kurs.Load lngKursID
blnKursLaeuft = Kurs.Termine.Erster.Beginn < Now() _
And Kurs.Termine.Letzter.Ende > Now()

statt (nur eine mögliche Implementierung)

rstTermine = dbs.OpenRecordset("SELECT Beginn, Ende " & _
"FROM tblKurstermine " & _
"WHERE KursID=" & lngKursID & " " & _
"ORDER BY Termin", dbOpenForwardOnly)
dtmKursBeginn = rstTermine.Fields("Beginn").Value
rstTermine.MoveLast
dtmKursEnde = rstTermine.Fields("Ende").Value

blnKursLaeuft = dtmKursBeginn < Now() _
And dtmKursEnde > Now()

Bemerkungen:
- Ändern sich die Tabellen- oder Feldnamen, muss im obigen Fall
lediglich der gut lokalisierbare Code der Kapselklassen leicht angepasst
werden, während im unteren Fall alle ähnliche Codeteile Zeile für Zeile
peinlichst genau nach notwendigen Änderungen durchgegangen werden.
- Obige Information, ob der Kurs läuft, ist in einer guten Kursklasse
selbstverständlich als berechnete Eigenschaft verfügbar:

blnKursLaeuft = Kurs.Laeuft ' ;-)


Abschließende Bemerkungen:
==========================

- Aus Sicht des Benutzers der Software lässt sich mit Klassen nichts
tun, was nicht auch ohne Klassen gegangen wäre. Klassen sind lediglich
ein Konstrukt für den Entwickler.
- Bei der Entwicklung mit selbstgebastelten Klassen kann die Entwicklung
des Codes wesentlich näher an der eigentlichen Problemstellung und
weiter weg von der technischen Grundlage (wie z.B. Datenstruktur) geschehen.
- Programmieren von Klassen ist mühsam,
programmieren mit Klassen ist kuhl!


HTH,
Paul
--
http://www.softconcept.at - Development, Solutions, Tools
http://access.primary.at - Wiener Access-Stammtisch
Bodo Greiner
2005-12-03 15:02:39 UTC
Permalink
Hallo Paul,

herzlichen Dank für Deine ausführliche Beschreibung! Ich werde mir das die
nächsten Tage genau durchlesen!

Gruß, Bodo
Thomas Möller
2005-12-03 17:55:53 UTC
Permalink
Hallo Paul,
Post by Paul Rohorzka
*V5) Bessere Lesbarkeit von Quellcode*
Oft werden für einen Vorgang, eine Berechnung, uä. mehrere Parameter
benötigt. Wenn diese Parameter in Form einer längeren Parameterliste
an eine Methode übergeben werden, ist ohne Zuhilfenahme von
Intellisense die Bedeutung der einzelnen Parameter oft nicht klar. Hier
kann das
Einstellen von Eigenschaftswerten eines Objekts und dann das Aufrufen
einer Methode klarer sein.
With myFTP
.Address = "ftp://meineseite.com"
.UserName = "ich"
.RemoteDir = "downloads"
.LocalDir = "\\data\public\internet\website\common"
.FileFilter = "*.zip"
.PutFiles
lngBytesTransmitted = .BytesTransmitted
End With
statt
lngBytesTransmitted = FtpPutFiles( _
"ftp://meineseite.com", _
"ich", _
"downloads", _
"\\data\public\internet\website\common", _
"*.zip")
- Das ist auch ein Beispiel, wie der Code bei der Verwendung von
Klassen oft geschwätziger wird. Das halte ich aber für einen Vorteil,
zumal wir viele Teile des Codetextes nicht selbst tippen müssen
(Autovervollständigen).
ich finde Dein Argument treffend.

Ich denke aber, dass sich ein ähnlicher Effekt auch ohne Klasse herstellen
lässt. Dazu kann man "benannte Parameter" verwenden. Das sieht dann ungefähr
so aus:

Call Test(intWert:=5, strText:="Hallo")

Private Sub Test(ByVal strText As String, ByVal intWert As Integer)

Debug.Print strText
Debug.Print intWert

End Sub

Man kann jeden Parameter, den man übergibt, mit seinem Namen und den Zeichen
":=" kennzeichen.
Dadurch kann man zum einen die von Dir gezeigte "Geschwätzigkeit" erreichen.
Es ist so aber auch möglich die Parameter in beliebiger Reihenfolge zu
übergeben.


CU
--
Thomas

Homepage: www.Team-Moeller.de

TM-DateiFunktionen: Update auf Version 1.2 (seit 08.11.05)
Funktion "GetSpecialFolder" hinzugefügt.
Loading...