Lotus Notes / Domino Sonstiges > Projekt Bereich
Gang Of Four (GoF) Design Patterns für LotusScript on OO nachprogrammieren?
koehlerbv:
Matthias, natürlich gehört alles gekapselt, was irgendwann wiederkehren wird. Also sehr, sehr viel.
Ich habe dafür ScriptLibs wie
- BasicLib: Was jede DB braucht. Ich habe mir mittlerweile abgewöhnt, hier scheinbar "unnötige" Routinen pro App zu entfernen. BasicLib ist BasicLib, und fertig.
- ReportRoutines: Routines für das Logging (wenn erforderlich)
- AgentTools: Some tricky routines to manipulate the agent settings ;D
- CommonAppLib (was die Klasse von Apps - so vorhanden - immer braucht)
- CommonAppUILib (was die Klasse von Apps - so vorhanden - immer braucht)
Und dann kommen SpecialAppLib, SpecialAppUILib etc.
Die Libs (ausser den Special...Lib) werden per %INCLUDE eingelesen. Wenn sich also eine neue Erkenntnis ergibt, ist überall Neukompilierung (und ggf. Anpassung) erforderlich, was ja bei den Basics nun überhaupt nicht schadet und dazu zwingt, "ein für allemal" gründlich zu programmieren.
Das war jetzt ein bisschen BP, aber nicht DP. Und es zwingt von vornherein dazu, wie man Libs sinnvol laufbaut (nicht, dass LibA LibB aufruft, diese dann LibC und diese wiederum LibA, was gerechterweise tierisch knallt und Kopfschmerzen bereitet, weil man 'ne Menge falsch gemacht hat).
Bernhard
Marinero Atlántico:
O.k. die Idee dieses Threads besteht gerade darin, praktischen code zu produzieren und dann daraus Theorie, Terminologie, Konzepte, Klassifizierungen, etc. abzuleiten.
Nur dafür brauche ich eben mehr Ruhe, die ich ja auch bald bekomme (trotz extra gig am 28. + evtl. 29. inklusive real existierender Vorbereitung).
Aber noch ein paar Theorieschnippsel, weil ich das zufällig gestern abend noch im GoF Buch gelesen habe:
--- Zitat ---- BasicLib: Was jede DB braucht. Ich habe mir mittlerweile abgewöhnt, hier scheinbar "unnötige" Routinen pro App zu entfernen. BasicLib ist BasicLib, und fertig.
- ReportRoutines: Routines für das Logging (wenn erforderlich)
- AgentTools: Some tricky routines to manipulate the agent settings Grin
- CommonAppLib (was die Klasse von Apps - so vorhanden - immer braucht)
- CommonAppUILib (was die Klasse von Apps - so vorhanden - immer braucht)
--- Ende Zitat ---
Wie noch zu sehen sein wird, sind Patterns etwas anderes (soll sich dann aus den Beispielen erschliessen und es wie ihr wisst, geht es nicht um besser oder schlechter).
Das weitestgehend sich auf c++ beziehende GoF Buch von 1995 bezeichnet solche wiederverwendkehrenden Libraries als
a) Toolkits
b) Frameworks
Patterns sind etwas explizit anderes.
Toolkits sind dabei wiederverwendbare Funktionsbibliotheken, die ein breites Anwendungsspektrum für einen Haufen an Stellen in einer Menge von Anwendungen haben, z.B. eine IO-Library oder eben sowas wie die beiden CommonAppxxx Libraries.
Frameworks haben ein enger definiertes Anwendungsspektrum. Z.B. ein Framework um alle möglichen verschiedenen Graphen zu erzeugen, oder pdf Dokumente, oder eben Agenten-Settings zu manipulieren (Notes) oder für Logging.
In Java sind die Toolkits (und die Frameworks, etwa für Regular Expressions) Bestandteil der "core Library". Deshalb sind da so viele Klassen.
Patterns sind etwas weniger konkretes und code ist immer nur ein Beispiel für die Implementierung eines Patterns. Ausserdem sind sie "kleiner". Ein Toolkit oder ein Framework kann immer aus mehreren Pattern bestehen aber ein Pattern nie aus einem Toolkit oder Framework.
Hört sich erstmal esoterisch an, aber die Perspektive ist eben anders. Es ist noch nicht mal kompliziert.
Macht euch nicht so einen Kopf und wartet auf die Beispiele.
Patterns sind ausserdem für die Programmierpraxis etwas sehr konkretes. Gerade Einsteiger-OO Bücher stellen OO in aller Regel zunächst immer aus der Analyse-Perspektive da. Ein Aufgabenbereich wird als Klassen/Objekte wiedergegeben, die miteinander in Beziehung stehen, bzw. miteinander interagieren. Diese Klassen/Objete sind Repräsentationen von der realen Welt (Als Beispiel: Student, Kurs, Raum).
Wirklicher Code wird dann aber aus dieser Ananlyse-Perspektive in eine Design-Perspektive übertragen, woraus dann der code entsteht. Die Anwendung aus dieser viel code-näheren Design Perspektive sieht dann ganz anders aus. Eine Menge an Klassen sind einfach keine Repräsentationen von Objekten in der Realen Welt, sondern mehr so Dinge, die die Anwendung zusammenhalten. (s. Bilder: Eclipse screen shot ist code, was unmittelbar aus Design folgt. Anzahlmässig viel mehr Klassen als in Analyse.)
Und um herauszufinden, welche Klassen man braucht und wie man diese zusammensetzt, um eine Analyse umzusetzen, braucht es eben diese Pattern.
Und es gibt auch nur 23 GoF Pattern (sind aus OO-Sicht die fundamentalsten, die es gibt). Und die sind noch nicht mal gleich "wichtig". Und ausserdem ähneln sie sich teilweise sehr.
wenn das euch verwirrt, tut es als schöngeistiges Gequatsche ab
Axel
Beispiele folgen
Marinero Atlántico:
1. Es gibt code.
2. Gof Design Patterns sind nicht irgendwelche „genialen“ Bibliotheken, sondern im-ersten-Blick-nicht-sehr-offensichtliche-echt wertvolle Hinweise zur Erstellung von flexibel anpassbaren OO-Code. Das Thema besitzt starke Abhängigkeiten zu anderen Teilen der OO-Theorie, so dass ich die erst mal versuche einfach darzulegen, wie ich diese sehe. Und zwar anhand von konkreten Code.
Ich habe beschlossen, die Designpatterns in eine Art Konsoleninfrastruktur mit LogDatenbank zu tun.
Dafür gibt es in Domino das Alog4.ntf template:.
Also bitte:
1. Neue Datenbank erstellen
2. Erweiterte Templates anhaken (show advanced templates)
3. Agent Log auswählen (filename: alog4.ntf)
4. Als Filename habe ich genommen HF_DP\ALog.nsf, als Name „Alog for HF_DP code“ (die krude Mischung aus Englisch und Deutsch ist so). Ihr könnt auch etwas anderes nehmen. Besser lokal installieren.
Als Datenbank für den Designpatterns code gibt es die Datenbank HF_DP.nsf (s. Attachment, im Administrator unterzeichnen ist immer eine gute Idee). Diese irgendwo besser im lokalen NotesData anlegen (z.B. im Verzeichnis HF_DP).
Wenn ihr die Datenbank auf eurem Rechner habt, geht ihr zur Ansicht Konfiguration. Da gibt es einen „Erzeugen/Konfiguration Logger“ Aktionsbutton. Das Dokument ist aber schon da. Dieses bitte bearbeiten. Ggbfls den Speicherort der Ressource LogDatenbank, die ihr eben erzeugt habt anpassen.
Die Werte sind:
Server: (im Sinne von <leer>
Datenbankpfad: HF_DP\Alog.nsf
Default Identifier: DEFAULT (eigentlich egal)
Nun befinden sich in der Datenbank HF_DB 2 Skriptlibraries, in denen je eine Klasse das Auslesen des Konfigurationsdokument und die Kommunikation mit dem NotesLog-Objekt unterstützen (Designer öffnen und Überblick, nicht Durchblick verschaffen).
Dabei benutzt ein Objekt der Klasse Logger ein Objekt der Klasse ConfigDocWrapper (s. code).
Jede dieser Klassen hat 1, eine, una, one Aufgabe:
- Logger regelt das mit dem Logging
- ConfigDocWrapper kann Konfigurationsdokumente auslesen.
Gemäss objektorientierter Analyse sollen Klassen kohäsiv sein. D.h. sie sollen 1 thematische Aufgabe übernehmen. Manchmal ist es nicht so einfach herauszufinden, was nun sinnvollerweise 1 thematische Aufgabe darstellt. Oft ist es einfach.
Hier habe ich schon viel Unsinn in bestehenden code gesehen. Ich mein, man muss wirklich kein mega-guru sein, um auf die Idee zu kommen, dass eine Konstruktion mit zwei Klassen wo eine Klasse, die gleichzeitig xml schreibt, LSA Konfiguration ausliest, weitere Dateien erzeugt mit einer Klasse kommuniziert, die Notes Konfiguration ausliest und durch eine NotesView iteriert möglicherweise nicht so besonders gut thematisch gegliedert ist.
Das aber nur am Rande, da es hier mehr um OO-Design gehen soll.
Ansonsten sind die beiden Klassen in den SkriptLibs in HF_DP.nsf von einem OO Standpunkt aus fragwürdig. Der Programmierer dieser Klassen besitzt vielleicht einen gewissen tragischen, möglicherweise genetisch bedingten Hang zur chronischen Underperformance. Gerade diese Schwächen können aber im weiteren Verlauf des Threads ganz nett sein, um OO-Design-Problematiken aufzuzeigen. Es wäre ganz gut, wenn die hier anwesenden Leute sagen könnten, wo aus ihrer Sicht die Schwächen liegen.
Diese beiden Klassen werden von den Agenten genutzt, in denen die Klassen für die weiteren Erörterungen drin sind. Erst mal ist dort der Agent DecoyDucksDontFly_Start mit den Klassen Duck, RedHeadDuck und MallardDuck. Es ist ein Entensimmulationsprogramm. Im Initialize des Agenten ist code, der Objekte der Klassen erzeugt und diese quasi als client nutzt.. Ihr könnt das erst mal ausprobieren, indem ihr diesem Agenten aus dem Notes Menü Agenten startet. Evtl. im Debugger anschauen was passiert.
Falls alles richtig läuft, werden ein paar Einträge in die Log-Datenbank geschrieben.
Logger benutzt ConfigDocWrapper, um die Log-Db zu finden.
Die Duck-Klassen in dem Agenten „DecoyDucksDontFly_Start benutzen Logger.
Marinero Atlántico:
Ich stelle hier erst mal kurz die beiden Klassen wie sie in der Datenbank benutzt werden als UML Klassendiagramm dar. Damit kann man am ganz gut ein paar OO-Grundlagen erklären.
Statische Sicht (UML-Klassendiagramm):
Marinero Atlántico:
Dieses Diagramm ist nicht so schwer zu lesen.
In den lustigen Karteikarten sind 3-teilige Dinger drin.
Oben in den 3-teiligen Dingern stehen Buchstabenfolgen drin, die extrem an die Namen der Klassen erinnern, von denen so eben die Rede war und die darüber hinaus auch noch im code der Datenbank stehen. Die 3-teiligen Dinger sind also Klassen.
Die sind in den Karteikarten drin und –aha- auf den Karteikarten stehen die Namen der SkriptLibs und Agenten, wo die Klassen drin sind.
Oben sind dann noch bekannte Domino Klassen.
Die Karteikarten heissen in UML packages. Die Notes-Klassen sind in einer –sagen wir – speziellen Art von packages namens Subsystem. So wichtig ist die Unterscheidung hier nicht.
Packages sind eine Art Container. Etwas, wo man was reintut. ScriptLibs und Agenten sind ja auch etwas, wo man Klassen reintut. Also passt dieses UML-Element wirklich sehr gut.
Die meisten Leser sollten schon mal gehört haben, dass Klassen Eigenschaften und Methoden haben. Im zweiten Teil der Klassen stehen die Eigenschaften und im 3. Teil die Methoden.
Das minus-Zeichen vor den Eigenschaften steht für den Zugriffs-Modifizierer private
Das plus-Zeichen vor den Methoden steht für den Zugriffs-Modifizierer public.
Was das genau ist, wird noch erklärt. Hier sind alle Eigenschaften private und alle Methoden public. Das ist nicht zwangsläufig so. Was es mit diesen Zugriffsmodifizierern auf sich hat, wird noch erklärt.
Die Domino-Klassen haben überhaupt keine Eigenschaften und Methoden eingetragen. Das ist aber nur, weil man in UML Teile weglassen kann. Die interessieren hier nicht und stehen sowieso in der Notes Hilfe.
Es interessiert mich nur, dass in den selbstgeschriebenen Klassen diese Domino-Klassen benutzt werden.
Zwischen den Klassen gibt es eine Menge Pfeile. An manchen steht <<is-a>>, aber an den meisten <<has-a>>. Wo <<is-a>> steht, sieht das Pfeilende anders aus als die wo <<has-a>> steht.
Normalerweise würde man in einem UML Diagramm nicht <<has-a>> und <<is-a>> reinschreiben, weil das in UML schon durch genau diese Formen der Pfeilenden ausgedrückt wird. Ich habs nur zur besseren Klarheit da reingeschrieben.
Beginnen wir mit den <<has-a>> Pfeilen.
Schaut euch die Klasse ConfigDocWrapper in der ScriptLib Configuration an.
Was steht dort oben:
Private vw As NotesView
Private docConfig As NotesDocument
Private keyConfig As String
Und wohin gehen die has-a Pfeile von Configuration im UML-Bild??
Zu NotesView und zu NotesDocument.
Und was steht da oben??
DocConfig as NotesDocument und vw As NotesView.
In den anderen Klassen finden sich im Code die <<has-a>> Beziehungen auch in den Attributen wieder. Ist auch logisch. <<has-a>> im Sinne von „hat-ein“ ist vom normalen Sprachgebrauch so was wie eine Eigenschaft.
Ob man eine Eigenschaft im code in UML als has-a Beziehung oder als Eigenschaft (2. Teil von Klasse) modelliert, befindet sich sowieso im Ermessen des Modellierers. Es gibt gewisse Argumente, warum bestimmte Eigenschaften als has-A Beziehungen dargestellt werden, aber das ist hier kein UML-Kurs und erst mal nicht so wichtig.
Has-A Beziehungen werden auch als Composition bezeichnet. Ein wichtiges Motto der GoF ist: Favour Composition over Inheritance. Ihr müsst das jetzt nicht verstehen. Wird später erklärt. Einfach im Unterbewusstsein aufnehmen. Wenn ihr den Thread zu Ende gelesen habt, wacht ihr als C#.NET Programmierer auf
Und die anderen Pfeile? Die is-a Pfeile?
Die stehen für Vererbungsbeziehungen (Inheritance).
A RedHeadDuck is a Duck.
A MallardDuck is a Duck.
Klingt logisch.
Und sieht man das auch im code?
Ja.
Public Class Duck
Public Class RedHeadDuck As Duck
Public Class MallardDuck As Duck
Das LS Schlüsselwort As steht für Vererbung oder anders ausgedrückt is-a Beziehungen.
In der nächsten Folge wird genauer die exakten technischen Wirkungen dieser Vererbung anhand des laufenden Codes erklärt (phate Debugger-Session). Diese sind in allen OO-Sprachen sehr ähnlich. Ihr könnt den Agenten starten und es euch schon mal im Debugger und der Log-DB anschauen. Vorweg schon mal das: (hab ich grad bei dem Microsoft Autor Jesse Liberty gelesen): Es gibt durch Vererbung aus Design-Sicht 2 Effekte:
- tendentiell schon mal problematische code inheritance
- als zweiten und wichtigeren Effekt Polymorphismus.
Danach wird der Code des Entensimulationsprogramms erweitert. Da wird deutlich, was an Vererbung problematisch ist und warum die GoF Autoren „Favor composition over inheritance“ für eine gute Idee halten. Das Dilemma des Entensimulationsprogramms wird durch das Strategy Pattern angegangen. Das wird die erste Anwendung eines Patterns sein.
Tipp für Logger/ConfigDocWrapper-Bashing: Schaut auf die Abhängigkeiten. Die has-a Pfeile sind Abhängigkeiten. Welche konkreten weiteren Anforderungen können an diese Klassen gestellt werden (z.B. bei Wiederverwendung in einem konkreten anderen Kontext). Verbesserungsvorschläge?
Navigation
[0] Themen-Index
[#] Nächste Seite
[*] Vorherige Sete
Zur normalen Ansicht wechseln