Das Notes Forum

Domino 9 und frühere Versionen => Entwicklung => Thema gestartet von: TMC am 18.06.04 - 22:35:13

Titel: Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 18.06.04 - 22:35:13
Ich bin bezügl. Klassen ein Anfänger, da ich noch nie wirklich größere Klassen erstellt habe.

Wie baut Ihr sinnvoll Klassen auf?

Ich nehme als Beispiel eine History-Scriptlibrary, bisher hab ich alles als Subs & Functions in der Lib.

Was passiert:
A) User öffnet ein Dokument
+ Im Postopen werden zu überwachende Feldnamen und Feldinhalte jew. ein eine globale Variable (Array) gesetzt
B) User speichert ein Dokument
+ Im PostSave (nicht Querysave da RTF-Überwachung inclusive):
     - Array-Vergleich vorher / nachher, wenn keine Änderung: mache nix
     - setze History-Log zusammen, dabei Unterschied ob RTF oder nicht
     - Definiere 1. und 2. "Spalte" (durch Tab getrennt), hier Datum und Username
     - Setze String für Textfeld zusammen
     - Hänge Änderungen ans Textfeld an
     - Save

Ziel ist für mich, die Klasse prinzipiell für viele DB's verwenden zu können. Dinge wir den Namen des History-Feldes, die Anzahl der Historien-Einträge, etc. will ich der Klasse übergeben.
Bisher setze ich hier in der ScriptLib auch Standard-Functions wie Explode, Implode, CompareArray etc. ein.

Ich bin für jeden Ansatz dankbar, wie ich das in eine Klasse übernehmen könnte.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 18.06.04 - 22:43:05
Nachtrag:
Gibt es irgend eine (3rdParty) - Möglichkeit für Notes-LS, um Klassen übersichtlicher als im Designer zu entwickeln? Ich denke da an eine Browse-Möglichkeit. Dass kompilieren in 3rd-Party wohl nicht möglich ist, ist mir klar, aber zumindest um den Überblick zu behalten wäre das wohl sehr hilfreich.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 19.06.04 - 03:17:18
ich kenne leider kein Tool, das objektorientierte Programmierung mit Notes irgendwie erleichtert. Hier im Forum wurde mal ein Projekt geboren (lssEclipse), ich glaube aber, dass es nicht mehr sehr lebendig ist.

zum Ansatz, den du wünschst:

schreib doch mal kurz auf, was diese Klasse können soll und, ggf., mit welchen anderen Klassen sie kooperieren soll.

und noch eine Frage hinterher:
warum möchtest du eine Klasse haben? Du hast ja scheinbar schon etwas funktionierendes in deiner History-Scriptlibrary...
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 19.06.04 - 18:59:31
Schade dass es da wohl nichts gibt, um Klassen besser bearbeiten zu können. Wenn ich mir überlege, dass ich den jetzigen Code komplett in die Declarations kopiere: ich würde k. wenn dann Anpassungen nötig sind  :P

warum möchtest du eine Klasse haben? Du hast ja scheinbar schon etwas funktionierendes in deiner History-Scriptlibrary...
Sehr berechtigte Frage, ich glaube ich werde es dabei lassen. Die Subs/Functions, die ich ausschließlich in dieser ScriptLib verwende, mache ich noch zu "Private", dokumentiere das ganze in den Declarations, und dann sollte das gut so sein.

Mein Ziel war, etwas dabei zu lernen. Aber ich denke das gehe ich mal neu an bei einem anderen passenden Projekt.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: Semeaphoros am 19.06.04 - 19:38:27
Es gibt da so einen Kompromiss, der manchmal ganz nützlich ist: man defniert eine Klasse, die einzelnen Member-Routinen machen aber nichts anderes, als eine normale Sub oder Function aus der gleichen ScriptLib auf. Man achtet dann natürlich darauf, dass beim Verwenden der Klasse nie die Klasse selbst dadurch umgangen wird, dass man die Subs und Functions direkt aufruft. Damit hat man dann aber die gewünschte gewohnte Designer-Darstellung für seine "Methoden".

Class Beispiel
  daten as Datentyp

sub MemberMachIrgendwas (Param As String)
   Call ExtMachIrgendwas (Param)
End Sub

function MemberMachWasAnderes (X as Integer) As String
  MemberMachWasAnderes = ExtMachWasAnderes(X)
End Funcition

End Class


'****

sub ExtMachIrgendwas (Param As String)
  REM Hier der effektive Code
End Sub


'****

function ExtMachWasAnderes (X as Integer) As String
   ExtMachWasAnderes = "Die durchzuführende Berechnung mit X"
End Function
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 19.06.04 - 19:48:46
Danke, das klingt interessant Jens. Werde ich mir mal im Detail ansehen.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 20.06.04 - 00:40:04

warum möchtest du eine Klasse haben? Du hast ja scheinbar schon etwas funktionierendes in deiner History-Scriptlibrary...
Sehr berechtigte Frage, ich glaube ich werde es dabei lassen. Die Subs/Functions, die ich ausschließlich in dieser ScriptLib verwende, mache ich noch zu "Private", dokumentiere das ganze in den Declarations, und dann sollte das gut so sein.

Mein Ziel war, etwas dabei zu lernen. Aber ich denke das gehe ich mal neu an bei einem anderen passenden Projekt.

Ich denke, du kannst auch was lernen, wenn du ein objektorientiertes History-Framework entwickelst.
Meine Frage sollte nicht bewirken, dass du einen Rückzieher machst. Ich wollte wirklich nur wissen, warum - und 'lernen' ist schon ein ziemlich guter Grund.

Also nochmal: der erste Schritt ist, aufzuschreiben, was das Ding alles können soll. Los gehts...
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 20.06.04 - 16:41:13
Los gehts...

OK  ;)

Der Grobablauf steht schonmal ganz oben.

Hab mir mal überlegt das etwas zu gliedern:
(http://www.atnotes.de/attachments/historyclass_01.gif)

Wo es imho schon mal hängt ist, dass ich im Postopen-Event was in eine (in der Maske definierten) globalen Variable schreibe, worauf ich im Postsave wieder zugreifen will. Kann ich das in der Klasse machen oder muss ich das direkt im Postopen/Postsave machen?
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 20.06.04 - 16:47:31
OK, was ich der Bible von Rocky und Brian entnommen habe, ist das schon mal ein must-have in jeder Klasse:

(http://www.atnotes.de/attachments/historyclass_02.gif)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: koehlerbv am 20.06.04 - 17:08:10
Schau mal hier, Matthias:
http://www-106.ibm.com/search/searchResults.jsp?searchType=1&searchSite=dW&query=%22bruce+perry%22&searchScope=lotus&Search.x=23&Search.y=13 (http://www-106.ibm.com/search/searchResults.jsp?searchType=1&searchSite=dW&query=%22bruce+perry%22&searchScope=lotus&Search.x=23&Search.y=13)

Meines Erachtens ein hervorragender Einstieg !

Was Deine Klassen-Methoden angeht: Du kannst entweder die sowieso erforderliche Methode New dafür hernehmen, um
- alle globalen Variablen (als members Deiner Klasse) mit dem Ausgangsstatus zu versehen (in PostOpen) oder
- dieser erstmal nur "leer" zu instantiieren. Dann müsstest Du in PostOpen gleich nachschieben, die Methode "GetOriginalValues" zu verwenden (die das tun sollte, was ihr Name verspricht)
- In QuerySave oder PostSave rufst Du dann Deine Methode "WriteDifferences" auf, die den jetzt aktuellen Stand mit den Member-Variablen Deiner Klasse vergleicht und entsprechend verfährt.
Sowas wie die Prüfung auf die max. Grösse eines Textfeldes sollte dann innerhalb der Klasse als Private deklariert werden.

HTH,
Bernhard

PS: Sag an, wenn es wieder klemmt. Die ersten Schritte sind IMHO erstmal sehr schwer, aber wenn man darüber erstmal hinaus ist, fallen einem wirklich die "Schuppen aus den Haaren"  ;)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 20.06.04 - 17:23:41
ok.
vorneweg: als geschickt würde ich es empfinden, midestens zwei Klassen zu erstellen:
Klasse History
Klasse HistoryEntry

wobei HistoryEntry eine abstrakte Klasse ist und als Basisklasse für zwei andere Klassen dient:
Klasse RTFHistoryEntry
Klasse TextHistoryEntry

(abstrakte Klasse bedeutet, dass von dieser Klasse nie eine Instanz/ ein Objekt erzeugt wird. Basisklasse bedeutet, dass von ihr andere Klassen abgeleitet sind, die ihre Methoden und Attribute erben)

in der Praxis könnte das dann so aussehen, dass ein History-Objekt ermittelt, welcher Eintrag (Text oder RTF) erzeugt werden muss.
Das kann es z.B. anhand eines Feldwerts oder der Präsenz bzw. Absenz eines Felds im Notesdokument entscheiden.
Das History-Objekt erzeugt dann ein entsprechendes HistoryEntry-Objekt und übergibt diesem die Daten, die es enthalten soll.
Das HistoryEntry-Objekt kennt das Notesdokument und weiß, wie es sich ins darin verewigen muss (also entweder als RTF oder als Text).
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 20.06.04 - 17:31:10
Wo es imho schon mal hängt ist, dass ich im Postopen-Event was in eine (in der Maske definierten) globalen Variable schreibe, worauf ich im Postsave wieder zugreifen will. Kann ich das in der Klasse machen oder muss ich das direkt im Postopen/Postsave machen?

Du kannst die Behandlung von Events, die von der Maske ausgelöst werden, an die Klasse delegieren (das steht auch in dem Artikel, den Bernhard anführt).

Stichwort 'On Event x From y Call z'
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: koehlerbv am 20.06.04 - 17:47:51
Ich würde das für den Anfang einfacher halten. EINE Klasse, und diese
- wird in den Declarations der Form instantiiert
- New löst entweder das Belegen der zu überwachenden Felder im Originalzustand aus oder es wird mit einer eigenen Methode der Klasse diese Belegung aufgerufen (auf jeden Fall: Ein Array der zu überwachenden Feldnamen wird an New übergeben)
- Ein Compare/Write History vergleicht und schreibt dann das History field.

Das Ganze kann man dann ja beliebig ausbauen  ;)

Bernhard
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 20.06.04 - 17:56:59
Danke für Eure Tipps !

wobei HistoryEntry eine abstrakte Klasse ist und als Basisklasse für zwei andere Klassen dient

Hab ich das so jetzt richtig verstanden?

(http://www.atnotes.de/attachments/historyclass_03.gif)


Was mir da noch nicht klar ist:
Ich (bzw. der Postopen- oder Postsave - Event) kommuniziere nur mit der Klasse "History" ? Die in den anderen Klassen benötigten Dinge gebe ich intern dann entsprechend weiter?
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 20.06.04 - 17:58:35
Wo es imho schon mal hängt ist, dass ich im Postopen-Event was in eine (in der Maske definierten) globalen Variable schreibe, worauf ich im Postsave wieder zugreifen will. Kann ich das in der Klasse machen oder muss ich das direkt im Postopen/Postsave machen?

Du kannst die Behandlung von Events, die von der Maske ausgelöst werden, an die Klasse delegieren (das steht auch in dem Artikel, den Bernhard anführt).

Stichwort 'On Event x From y Call z'

Hier als Beispiel dazu ein Ausschnitt aus einer Klasse
Im QueryOpen-Event des Dokuments wird ein Objekt dieser Klass erzeugt. Alle für mich interessanten Events, die danach ausgelöst werden, werden von diesem Objekt behandelt (das wird in dem Konstruktor (Sub New) festgelegt).

Public Class xyz
   Private m_udFrontendDoc As notesuiDocument
   Private m_docBackendDoc As notesDocument

   Sub New(udCurrentDoc As notesUIDocument)
%REM
------------------------------------------------------------------------------------------------------------------------
Author:      TV
Date:      23.10.2003
Description:   Ich initialisiere meine Attribute und sorge dafür, dass Events aus dem FrontendDocument
         durch mich bearbeitet werden.
Parameter:   udCurrentDoc: NotesUIDocument
            Das Frontend-Dokument, das die Agent-Informationen anzeigt
Return Value:   <Name, Datentyp und Erklärung des Rückgabewertes>
History:      
------------------------------------------------------------------------------------------------------------------------
%END REM   
      
      'Frontend-Dokument und zugehöriges Backend-Dokument besorgen
      Set m_udFrontendDoc = udCurrentDoc
      
      'Achtung! Das BackendDokument ist in normalen Masken erst im Postopen Event verfügbar!
      'In Dialogboxen kann es schon im QueryOpen Event verfügbar sein.
      Set m_docBackendDoc = udCurrentDoc.Document
      
      'auf Events des FrontendDokuments reagieren
      On Event Postopen From m_udFrontendDoc Call ProcessPostopen
      On Event Postrecalc From m_udFrontendDoc Call ProcessPostrecalc
      
      'Zeitgesteuerte Agenten suchen und dem Benutzer zur Auswahl anzeigen
      Call initAgentMap()   
      Call collectScheduledAgents
      Call m_docBackendDoc.ReplaceItemValue(ST_DEFI_AMGR_AvailableAgents, m_asScheduledAgents)
   End Sub

   Sub ProcessPostopen(Source As Notesuidocument)
%REM
------------------------------------------------------------------------------------------------------------------------
Author:      TV
Date:      23.10.2003
Description:   Ich aktualisiere das FrontendDokument
Parameter:   <Name, Datentyp und Erklärung des Übergabeparameters>
Return Value:   <Name, Datentyp und Erklärung des Rückgabewertes>
History:      
------------------------------------------------------------------------------------------------------------------------
%END REM
      Call m_udFrontendDoc.Refresh()
   End Sub

End Class
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 20.06.04 - 18:08:26
das könnte jetzt etwas wirr werden, aber wenn wir damit jetzt schon anfangen, dann machen wir das gleich gescheit.
Ich hab mal das Klassendiagramm mit UML gemalt. Das ist einfach der Standard, um sowas zu modellieren. Das Diagramm hängt als Attachment hier dran.

Die Kästen sind Klassen (im Moment noch ohne Methoden/Attribute).
Ganz oben in jedem Kasten steht der Klassenname, gefolgt von den Attributen und den Methoden.
Kursiv geschrieben Klassennamen bedeuten, die Klasse ist abstrakt (von ihr wird keine Instanz erzeugt).
Die Linien mit den großen Pfeilen am Ende heißen Genrealisierung ('ist ein')
Die Linien ohne Pfeile sind ungerichtete Assoziationen ('gehört zu', 'hat')
Die Zahlen, die bei diesen Assoziationen stehen sind die Kardinalitäten  (bestimmt bekannt aus ERD. 'Zu einem History-Objekt gehören n HistoryEntry-Objekte)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 20.06.04 - 18:22:31
Was Deine Klassen-Methoden angeht: Du kannst entweder die sowieso erforderliche Methode New dafür hernehmen, um
- alle globalen Variablen (als members Deiner Klasse) mit dem Ausgangsstatus zu versehen (in PostOpen) oder
- dieser erstmal nur "leer" zu instantiieren. Dann müsstest Du in PostOpen gleich nachschieben, die Methode "GetOriginalValues" zu verwenden (die das tun sollte, was ihr Name verspricht)
Du kannst die Behandlung von Events, die von der Maske ausgelöst werden, an die Klasse delegieren (das steht auch in dem Artikel, den Bernhard anführt).
Stichwort 'On Event x From y Call z'

Was mir noch überhaupt nicht klar ist:

Ich habe bisher u.a. folgenden Code in der Maske (Auszüge):

Global Declarations
Code
Dim vGlobalHistoryFields As Variant
Dim vGlobalHistoryFieldTitles As Variant
Dim vGlobalHistorySource As Variant

PostOpen
Code
   vGlobalHistoryFields = fExplode(CHISTORYFIELDS, "##")
   vGlobalHistoryFieldTitles = fExplode(CHISTORYFIELDTITLES, "##")
   If Not Source.IsNewDoc Then
           'Write field values in global variable
      vGlobalHistorySource = fHistoryStoreItemValuesInArray(doc, vGlobalHistoryFields)
   End If

Was passiert da:
Es werden die zu überwachenden Feldnamen und die Item-Inhalte als Array in die globalen Variablen der Maske gesetzt.
Warum mach ich das:
Im Postsave hole ich mir die globalen Variable-Inhalte und mach was damit (vergleichen, etc.).

Jetzt die Frage:
Was kann ich davon in eine Klasse 'outsourcen' ? Kann ich die in der Maske ge-dim-ten  Variablen in einer Klasse setzen (ich will ja im PostSave wieder auf die im Postopen gesetzten Variablen wieder zurückgreifen können)? Oder muss ich das im Masken-Event erledigen?

(Ich hoffe dass ich die Frage einigermaßen klar rüberbringe....)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 20.06.04 - 18:27:14
Was mir da noch nicht klar ist:
Ich (bzw. der Postopen- oder Postsave - Event) kommuniziere nur mit der Klasse "History" ? Die in den anderen Klassen benötigten Dinge gebe ich intern dann entsprechend weiter?

Ja, genau, du erzeugst ein History-Objekt im Postopen-Event, und das wars dann schon an Code, den du in der Maske benötigst.

Wenn du das wirklich zur Übung machen willst, um OOx zu lernen dann würde ich mal darüber nachdenken, ob wir evtl. nicht eine Klasse Dokument brauchen (ich hab das schon in meinem Diagramm angedeutet)
Das wäre in meinen Augen korrekt.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 20.06.04 - 18:35:30

Ich habe bisher u.a. folgenden Code in der Maske (Auszüge):

Global Declarations
Code
Dim vGlobalHistoryFields As Variant
Dim vGlobalHistoryFieldTitles As Variant
Dim vGlobalHistorySource As Variant

PostOpen
Code
   vGlobalHistoryFields = fExplode(CHISTORYFIELDS, "##")
   vGlobalHistoryFieldTitles = fExplode(CHISTORYFIELDTITLES, "##")
   If Not Source.IsNewDoc Then
           'Write field values in global variable
      vGlobalHistorySource = fHistoryStoreItemValuesInArray(doc, vGlobalHistoryFields)
   End If

aha, so machst du das. vGlobalHistoryFields sind die Felder, die beobachtet werden sollen, stimmts?
Mein erster Gedanke ist, dass wir hier wieder einen Kandidaten für eine Klasse haben. Ich muss mal kurz nachdenken.
Aber egal, was dabei rauskommt, du solltest das alles aus der Maske rausbringen. Ok, die Information, welche Felder beobachtet werden sollen, kann man evtl. in der Maske lassen, aber keine Logik
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 20.06.04 - 18:44:47
das könnte jetzt etwas wirr werden, aber wenn wir damit jetzt schon anfangen, dann machen wir das gleich gescheit.
Ich hab mal das Klassendiagramm mit UML gemalt. Das ist einfach der Standard, um sowas zu modellieren. Das Diagramm hängt als Attachment hier dran.

Die Kästen sind Klassen (im Moment noch ohne Methoden/Attribute).
Ganz oben in jedem Kasten steht der Klassenname, gefolgt von den Attributen und den Methoden.
Kursiv geschrieben Klassennamen bedeuten, die Klasse ist abstrakt (von ihr wird keine Instanz erzeugt).
Die Linien mit den großen Pfeilen am Ende heißen Genrealisierung ('ist ein')
Die Linien ohne Pfeile sind ungerichtete Assoziationen ('gehört zu', 'hat')
Die Zahlen, die bei diesen Assoziationen stehen sind die Kardinalitäten  (bestimmt bekannt aus ERD. 'Zu einem History-Objekt gehören n HistoryEntry-Objekte)

Danke für die Tipps und die Zeichnung.
Wo "malt" man sowas am besten? Ich habe hier MS Visio 2002. Na ja, ist damit sicherlich machbar. Werde mir mal ein paar Visio-Shapes dafür zusammenzimmern (wenn diese nicht eh schon dabei sind).
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 20.06.04 - 18:52:28
das könnte jetzt etwas wirr werden, aber wenn wir damit jetzt schon anfangen, dann machen wir das gleich gescheit.
Ich hab mal das Klassendiagramm mit UML gemalt. Das ist einfach der Standard, um sowas zu modellieren. Das Diagramm hängt als Attachment hier dran.

Die Kästen sind Klassen (im Moment noch ohne Methoden/Attribute).
Ganz oben in jedem Kasten steht der Klassenname, gefolgt von den Attributen und den Methoden.
Kursiv geschrieben Klassennamen bedeuten, die Klasse ist abstrakt (von ihr wird keine Instanz erzeugt).
Die Linien mit den großen Pfeilen am Ende heißen Genrealisierung ('ist ein')
Die Linien ohne Pfeile sind ungerichtete Assoziationen ('gehört zu', 'hat')
Die Zahlen, die bei diesen Assoziationen stehen sind die Kardinalitäten  (bestimmt bekannt aus ERD. 'Zu einem History-Objekt gehören n HistoryEntry-Objekte)

Danke für die Tipps und die Zeichnung.
Wo "malt" man sowas am besten? Ich habe hier MS Visio 2002. Na ja, ist damit sicherlich machbar. Werde mir mal ein paar Visio-Shapes dafür zusammenzimmern (wenn diese nicht eh schon dabei sind).

sind normalerweise schon dabei. bei uns auf der Webseite kann man sich auch welche runterladen
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 20.06.04 - 18:53:28
aha, so machst du das. vGlobalHistoryFields sind die Felder, die beobachtet werden sollen, stimmts?
Mein erster Gedanke ist, dass wir hier wieder einen Kandidaten für eine Klasse haben. Ich muss mal kurz nachdenken.
Aber egal, was dabei rauskommt, du solltest das alles aus der Maske rausbringen. Ok, die Information, welche Felder beobachtet werden sollen, kann man evtl. in der Maske lassen, aber keine Logik

vGlobalHistoryFields ist sehr unglücklich gewählte Bezeichnung, sollte besser heissen "vGlobalHistoryFieldValues". Das sind die Item-Inhalte.
"vGlobalHistoryFieldTitles" sind die Namen der Items/Felder, die überwacht werden sollen.

Zur eigentlichen Frage: Kann ich eine globale Masken-Variable von einer Klasse aus setzen oder muss ich das im Masken-Event (hier: PostOpen) erledigen? Ziel ist ja, dass ich in einem anderen Masken-Event (Postsave) wieder auf die Werte zurückgreifen kann.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 20.06.04 - 19:00:08
die globale Maskenvariable wird zum Attribut (Property) der Klasse

Class x
   Private m_vaValues as Variant

   Public Property Set Values as Variant
      m_vaValues = Values
   End Property

   Public Property Get Values as Variant
      Values = m_vaValues
   End Property


End Class

(weiß nicht, ob das mit den Get/Set-Funktionen syntaktisch so korrekt ist)

dann hast du die Werte für die Lebenszeit deines Objekts zur Verfügung
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 20.06.04 - 19:02:14
sind normalerweise schon dabei.

Stimmt  :D

(http://www.atnotes.de/attachments/historyclass_04.gif)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 20.06.04 - 19:07:33
die globale Maskenvariable wird zum Attribut (Property) der Klasse

Class x
   Private m_vaValues as Variant

   Public Property Set Values as Variant
      m_vaValues = Values
   End Property

   Public Property Get Values as Variant
      Values = m_vaValues
   End Property


End Class

(weiß nicht, ob das mit den Get/Set-Funktionen syntaktisch so korrekt ist)

dann hast du die Werte für die Lebenszeit deines Objekts zur Verfügung

Wann ist denn mein Objekt tot?
Ich dachte, es ist z.B. dann tot, wenn das "End Sub" z.B. vom PostOpen-Event aufgerufen wird? Oder überlebt dies das Objekt?
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 20.06.04 - 19:15:21
kommt drauf an, wo du es deklarierst.
wenn du es im Sub Postopen deklarierst, ist es danach tot.

wenn du es in den Declaration der Maske deklarierst und im Postopen erzeugst, dann hast du es bis zum Terminate-Event der Maske
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 20.06.04 - 19:16:34
Wann ist denn mein Objekt tot?

Ich kenne das auch aus anderem Kontext. Manchmal ist sowas hilfreich:
Set uidoc = Nothing
Da ansonsten u.U. ein anderes UI-Document im Fokus ist unter bestimmten (nicht immer nachvollziehbaren) Umständen - und somit das Objekt nicht 'tot' ist.....
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 20.06.04 - 19:20:22
kommt drauf an, wo du es deklarierst.
wenn du es im Sub Postopen deklarierst, ist es danach tot.

wenn du es in den Declaration der Maske deklarierst und im Postopen erzeugst, dann hast du es bis zum Terminate-Event der Maske

Jetzt geht mir langsam ein Licht auf :D

Ich muss verdammt nochmal meine Denkweise umstellen  ;)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 20.06.04 - 19:48:15
cool, Visio bietet da schon sehr viel, hier ein Update meines Modells (vieles fehlt noch, ist erstes Experiment):
(http://www.atnotes.de/attachments/historyclass_05.gif)

Was mir viel Spaß macht ist die logische Vorgehensweise. Kein Durcheinander. Alles strukturiert und logisch.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 20.06.04 - 19:49:59
ich hab mal ein Gerüst zusammengezimmert, das wir zur Diskussion verwenden können.
hier kommts:

Maske
'Options
Use "Document"
Option Declare
'Declarations
Dim myDoc as Document

Sub Postopen(Source As Notesuidocument)
   Set myDoc = New Document(source)
End Sub

Klasse Document
Option Declare
Use "History"
Public Class Document
   
   Private m_uidoc As NotesUIDocument
   Private m_doc As NotesDocument
   Private m_History As History
   
   Public Sub new (uidoc As NotesUIDocument)
      'initialisieren
      Set m_uidoc = uidoc
      Set m_doc = uidoc.Document
      Set m_History = New History(m_doc)
      On Event PostSave From m_uidoc Call ProcessPostSave   
   End Sub
   
   
   Private Sub ProcessPostSave(Source As NotesUIDocument)
      'nach dem Speichern des Dokuments muss die History geschrieben werden
      Call m_History.save()
   End Sub
End Class


Klasse History
Option Declare
Use "HistoryEntry"
Use "TextHistoryEntry"

Public Class History
   Private m_doc As NotesDocument
   Private m_vaHistoryFields As Variant
   Private m_InitialFieldValues As Variant
   Private m_SavedFieldValues As Variant
   Private m_HistoryEntry As HistoryEntry
   
   Public Sub new(doc As NotesDocument)      
      Set m_doc = doc
      
      'Ermitteln, welche Felder beobachtet werden sollen und die Werte der Felder einlesen
      Call getHistoryFields()
      Call readInitialValues()
      
      'Ermitteln, welche HistoryEntry-Art erzeugt werden muss
      
      '...Ich tu so, als ob ich ermittelt hätte, dass ich normalen Text schreiben muss
      Set m_HistoryEntry = New TextHistoryEntry
      '...
   End Sub
   
   Public Sub save()
      'die einzige Funktion, die nach aussen sichtbar ist
      Call readSavedValues()
      Call writeHistory()
   End Sub
   
   Private Sub getHistoryFields()
      'die zu prüfenden Felder ermitteln
      'zur Einfachheit mache ich hier feste Werte
      'denkbar wäre, die Feldnamen in einem Konfigurationsdokument zu halten und hier auszulesen
      Redim m_vaHistoryFields(0)
      m_vaHistoryFields(0) = "Subject"
   End Sub
   
   Private Sub readInitialValues()
      'die Anfangswerte lesen
      Dim i As Integer      
      Redim m_InitialFieldValues(Ubound(m_vaHistoryFields))
      For i = 0 To Ubound(m_vaHistoryFields)
         m_InitialFieldValues(i) = m_doc.GetItemValue(m_vaHistoryFields(0))
      Next
   End Sub
   
   Private Sub readSavedValues()
      'die gespeicherten Werte lesen
      Dim i As Integer      
      Redim m_SavedFieldValues(Ubound(m_vaHistoryFields))
      For i = 0 To Ubound(m_vaHistoryFields)
         m_SavedFieldValues(i) = m_doc.GetItemValue(m_vaHistoryFields(0))
      Next
   End Sub
   
   Private Sub writeHistory()
      'Werte vergleichen und Ergebnisse an den HistoryEntry geben
      'ich lasse zur Einfachheit die Logik fürs Vergleichen weg und nehme feste Einträge
      m_HistoryEntry.myDate = "20.06.2004"
      m_HistoryEntry.myName = "TV"
      m_HistoryEntry.myAction = "saved"
      
      'Eintrag ins Dokument schreiben
      Call m_HistoryEntry.save(m_doc)
   End Sub
End Class

Klasse HistoryEntry

Option Declare

Public Class HistoryEntry
   
   'ein Eintrag besteht immer aus drei Daten
   Private m_sDate As String
   Private m_sName As String
   Private m_sAction As String
   
'Get/Set-Methoden
   Public Property Set myDate As String
      m_sDate = myDate
   End Property
   Public Property Set myName As String
      m_sName = myName
   End Property
   
   Public Property Set myAction As String
      m_sAction = myAction   
   End Property
   Public Sub new()
      
   End Sub
   
   
   
   Public Sub save(doc As NotesDocument)
      'ich werde von den speziellen Klassen implementiert
      'sie wissen genau, wie das speichern aussieht.
   End Sub
End Class


Klasse TextHistoryEntry

Option Declare
Use "HistoryEntry"
Const FIELD_NAME = "Name"
Const FIELD_DATE = "Date"
Const FIELD_ACTION = "Action"

Public Class TextHistoryEntry As HistoryEntry
   
   
   Public Sub new()
      
   End Sub
   
   Public Sub save(doc As NotesDocument)
      'neuen Eintrag schreiben
      'zur Einfachheit überschreibe ich hier die aktuellen Werte
      'normalerweise müssen sie angehängt werden
      Call doc.ReplaceItemValue(FIELD_NAME, m_sName)
      Call doc.ReplaceItemValue(FIELD_DATE, m_sDate)
      Call doc.ReplaceItemValue(FIELD_ACTION, m_sAction)
      Call doc.Save(True, True)
   End Sub
   
End Class

was fehlt ist die Klasse für die RTF-History, aber es müsste klar sein, wie die zu machen ist.

bin gespannt, was ihr davon haltet. wie gesagt, das ist nur ein Diskussionsstartpunkt, ich behaupte nicht, dass das gut oder schlecht ist.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 20.06.04 - 19:56:33
cool, danke für Deinen Einsatz, Thomas  :D

Wir sind imho eigentlich schon mittendrin, im - von Jens ursprünglich geplanten - OO-Kurs  :)

Schau mir das gleich mal an....
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 20.06.04 - 20:06:13
cool, danke für Deinen Einsatz, Thomas  :D

Wir sind imho eigentlich schon mittendrin, im - von Jens ursprünglich geplanten - OO-Kurs  :)

Schau mir das gleich mal an....

kein Problem. Kann ich ja vielleicht sogar mal brauchen.

Ja, wir sind mitten in sowas drin, aber vermutlich nicht so, wie sich Jens das von didaktischer Seite her vorgestellt hat. Aber vielleicht ist es so auch nicht allzu schlecht, auch wenns etwas konfus ist.
Immerhin hast du mittlerweile schon drauf, wie man ein Klassendiagramm mit den notwendigsten Elementen malt. Das ist nicht das Schlechteste.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 20.06.04 - 20:16:33
Ja, wir sind mitten in sowas drin, aber vermutlich nicht so, wie sich Jens das von didaktischer Seite her vorgestellt hat. Aber vielleicht ist es so auch nicht allzu schlecht, auch wenns etwas konfus ist.
Immerhin hast du mittlerweile schon drauf, wie man ein Klassendiagramm mit den notwendigsten Elementen malt. Das ist nicht das Schlechteste.

Jo, etwas konfus das ganze. Hat sich wohl eben aufgrund meiner Anfrage so ergeben....  ;)

Hab hier mal den Code von Dir in eine R5 - DB kopiert (see attached)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 20.06.04 - 20:28:58
Noch eine Grundsatzfrage zu Public / Private:

Man nehme eine ScriptLibrary:

Per Default steht dort in den Options "Option Public".
Wenn ich dort eine Function erstelle, ist diese öffentlich verfügbar, sprich wenn ich ein Use "MeineScriptLib" in einer Maske einbaue, habe ich Zugriff auf die Routine.

Wenn ich eine Sub/Function mit "Private Sub...." oder "Private Function..." einleite, dann kann ich darauf nur in der ScriptLib zugreifen.

So kenn ich das zumindest.
Jetzt würde mich interessieren wie das umgekehrt ist:
Wenn da kein "Option Public" steht, ist die ScriptLib gar nicht verfügbar? Muss dann da "Option Private" stehen oder ist ein fehlendes "Option Public" automatisch ein "Option Private" ? Was ist wenn dann eine Sub/Function mit "Public Sub..." eingeleitet wird, ist diese dann auch z.B. in einem Masken-Event verfügbar (obwohl in den ScriptLib-Options nix steht oder "Option Private") ?

Ich habe wohl grad den Fehler gemacht, "Option Public" in den Script Libs stehen zu lassen, als ich Thomas' Code hineinkopierte.... (bin mir aber nicht sicher ob das relevant ist...)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 20.06.04 - 20:41:46
Was mir gerade eben auffällt in Deinem Code, Thomas:

Rocky Oliver schreibt in seiner "Bible", das alle Klassen immer eine "Delete sub" enthalten sollen, die vermisse ich hier jetzt.

Ich kann allerdings mangels Know-how nicht abschätzen, wie wichtig das ist .......
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 20.06.04 - 20:44:34
Hab hier mal den Code von Dir in eine R5 - DB kopiert (see attached)


ah, läuft. schon mal näher im Debugger angeschaut, was da abläuft?

im Prinzip sehr simpel.
beim Öffnen eines Notesdokuments erzeugst du ein Dokument, das Dokument erzeugt eine History, die History erzeugt einen HistoryEntry
nach dem Speichern sagt das Dokument zur History 'speicher dich', die gibt den Befehl an den HistoryEntry weiter und der schreibt die benötigten Informationen ins NotesDokument.

Jetzt die Erklärung, warum ich es geschickter finde, eine abstrakte HistoryEntry-Klasse und mehrere davon abgeleitete Klassen zu verwenden.

was passiert, wenn von uns eine dritte Art gefordert wird, eine Historie zu schreiben.
an meiner funktionierenden History-Klasse füge ich genau zwei Zeilen hinzu (switch/select - Statement)
und ich erstelle eine neue Klasse für die geforderte dritte Art.
Der Rest meiner Klassen bleibt auf jeden Fall unberührt und muss z.B. nicht nochmal getestet werden, was evtl der Fall bei nur einer Klasse wäre.
Wenn jetzt noch mehr History-Arten verlangt werden, kein Problem. Der Code bleibt klein und übersichtlich. Bei nur einer Klasse könnte es etwas unübersichtlich werden.

Eine Klasse für das alles wäre vollkommen ok gewesen, für sich ändernde Anforderungen aber vielleicht unflexibler als die Variante mit mehreren Klassen.
Ich hoffe, ihr versteht, was ich meine.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 20.06.04 - 20:47:23
Noch eine Grundsatzfrage zu Public / Private:

Man nehme eine ScriptLibrary:

Per Default steht dort in den Options "Option Public".
Wenn ich dort eine Function erstelle, ist diese öffentlich verfügbar, sprich wenn ich ein Use "MeineScriptLib" in einer Maske einbaue, habe ich Zugriff auf die Routine.

Wenn ich eine Sub/Function mit "Private Sub...." oder "Private Function..." einleite, dann kann ich darauf nur in der ScriptLib zugreifen.

So kenn ich das zumindest.
Jetzt würde mich interessieren wie das umgekehrt ist:
Wenn da kein "Option Public" steht, ist die ScriptLib gar nicht verfügbar? Muss dann da "Option Private" stehen oder ist ein fehlendes "Option Public" automatisch ein "Option Private" ? Was ist wenn dann eine Sub/Function mit "Public Sub..." eingeleitet wird, ist diese dann auch z.B. in einem Masken-Event verfügbar (obwohl in den ScriptLib-Options nix steht oder "Option Private") ?

Ich habe wohl grad den Fehler gemacht, "Option Public" in den Script Libs stehen zu lassen, als ich Thomas' Code hineinkopierte.... (bin mir aber nicht sicher ob das relevant ist...)

Wenn kein Option Public dasteht ist erstmal alles Private, also nur innerhalb des Moduls sichtbar.

Ich habe mir aus diversen Gründen angewöhnt, das Option Public aus ScriptBibliotheken rauszuschmeißen.
Wenn du das stehen lässt, ist das kein Problem, weil sowieso vor jeder Methode / jedem Attribut Private oder Public steht.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 20.06.04 - 20:51:13
Wenn kein Option Public dasteht ist erstmal alles Private, also nur innerhalb des Moduls sichtbar.

Ich habe mir aus diversen Gründen angewöhnt, das Option Public aus ScriptBibliotheken rauszuscheißen.
Wenn du das stehen lässt, ist das kein Problem, weil sowieso vor jeder Methode / jedem Attribut Private oder Public steht.

Nun geht mir ein weiteres Licht auf  :)
Ist imho auch ein Thema, was in den "Was ein Notes Entwickler immer beachten sollte" - Thread gut passt.... (natürlich dann mit Erklärung)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 20.06.04 - 20:54:45
Was mir gerade eben auffällt in Deinem Code, Thomas:

Rocky Oliver schreibt in seiner "Bible", das alle Klassen immer eine "Delete sub" enthalten sollen, die vermisse ich hier jetzt.

Ich kann allerdings mangels Know-how nicht abschätzen, wie wichtig das ist .......

die Methode dient zum Aufräumen.
warum er schreibt, dass man die unbedingt immer braucht, kann ich nicht so recht nachvollziehen.
Sowas braucht man z.B. wenn du bidirektionale Verbindungen zu anderen Objekten hast. Wenn dein Objekt zerstört wird, dann zeigen die Referenzen der anderen Objekte auf dieses Objekt ins Leere, deshalb ist es ratsam solche Verbindungen kurz vor dem Ableben zu lösen.
In unserem Fall sehe ich keine Notwendigkeit, irgendwas aufzuräumen
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 20.06.04 - 21:02:54
die Methode dient zum Aufräumen.
warum er schreibt, dass man die unbedingt immer braucht, kann ich nicht so recht nachvollziehen.
Sowas braucht man z.B. wenn du bidirektionale Verbindungen zu anderen Objekten hast. Wenn dein Objekt zerstört wird, dann zeigen die Referenzen der anderen Objekte auf dieses Objekt ins Leere, deshalb ist es ratsam solche Verbindungen kurz vor dem Ableben zu lösen.
In unserem Fall sehe ich keine Notwendigkeit, irgendwas aufzuräumen

Das von Dir hört sich plausibel an.
Rocky schreibt auch nur sehr allgemein und hat das Klassen-Kapitel seeehr kurz gehalten in seinem Buch.
Er schreibt: "(...) Your class requires 2 subs - New (used to create the class) and Delete (used to destroy the class and perform cleanup). (...) all classes should have a New sub and a Delete sub"

Dem Umfang der Bible entsprechend ist eh das Kap. "Creating LS Classes" imho sehr kurz gehalten (vielleicht 1 Seite Text, Rest ist Source Code), mir macht es den Anschein, als ob da schnell mal darüber hinweg gegangen wurde (obwohl das Buch selbst wirklich sehr gut ist).
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 20.06.04 - 21:10:34
beim Öffnen eines Notesdokuments erzeugst du ein Dokument, das Dokument erzeugt eine History, die History erzeugt einen HistoryEntry
nach dem Speichern sagt das Dokument zur History 'speicher dich', die gibt den Befehl an den HistoryEntry weiter und der schreibt die benötigten Informationen ins NotesDokument.

Hochinteressant.
Ich hab mir bisher mit meiner Subs/Function - orientierten Scribt-Lib immer wieder gedacht: Was kann ich noch verbessern.
Du hast es gerade gezeigt  ;)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 20.06.04 - 21:23:30
was findest du denn daran besser?
mit der alten Methode hats ja auch einwandfrei funktioniert.
was kann man noch verbessern?
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 20.06.04 - 21:33:57
was findest du denn daran besser?
mit der alten Methode hats ja auch einwandfrei funktioniert.

Gute Frage:
+ Weil ich damit nur noch Minimal-Code in den Masken-Events habe
+ besser wiederverwendbar (Copy&Play)
+ Wartung nur an 1 Stelle
+ Was ist wenn ich das auch noch den Querymodechange-Event einbinden muss (das wird so sein bei History: das Dok ist offen im Lesemodus, und User wechselt in Bearbeitungsmodus; ein Postopen-Code schlägt somit nicht zu); also selbe Zeile in Querymodechange und schon gefixt :-))

Meine ersten spontanen Eindrücke.....
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 20.06.04 - 21:38:48
was kann man noch verbessern?

Kann ich Dir erst beantworten, wenn ich das in einer Test-DB eingesetzt habe. Wird heute leider nicht mehr sein.
Ist für mich nicht ganz trivial das ganze, ich muss es erstmal live gesehen haben :-)
Weiteres Feedback zum Code kommt also noch  ;)

**Nachtrag**
"On Event PostSave " war für mich hier auch neu, kannte ich noch gar nicht, ist sehr interessant.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 21.06.04 - 22:24:09
Hab mal noch die im Code verwendeten Felder in der Maske ergänzt und ein paar Msgboxes ergänzt.


Generell erscheint mir trotz logischen Aufbau das Konstrukt mit den 4 Beispielklassen noch sehr komplex. Aber das sind wohl die Anfangsschwierigkeiten  ::)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 21.06.04 - 22:53:18
bei Fragen oder Problemen einfach nachhaken...
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 21.06.04 - 23:10:41
Generelle Frage zu Klassen:

Angenommen ich habe eine Array-Script-Lib. Spricht was dagegen die dort verwendeten Subs und Functions in Klassen zu verwenden?
Klar - ich meine wenn man in der Array-Lib was gravierendes ändert (z.B. Rückgabewert einer Function plötzlich anderer Datentyp, etc.etc.) dann zerlegt es alles.

Ist mehr eine generelle Frage..... Ich denke ich werde in Klassen auch bewährte Functions verwenden. Und die würd ich dann auch nach wie vor zentral irgendwo vorhalten wollen.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: koehlerbv am 21.06.04 - 23:14:14
IMHO: Dagegen spricht überhaupt gar nichts - ganz im Gegenteil.
Zitat
wenn man in der Array-Lib was gravierendes ändert (z.B. Rückgabewert einer Function plötzlich anderer Datentyp, etc.etc.) dann zerlegt es alles
Das tut es immer, Matthias - egal, ob in Classes oder "normalen" Functions oder Subs  ;)

Bernhard
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 21.06.04 - 23:15:54
Noch was generelles: Vermeidung rekursiver Aufruf:

Ich habe schon öfter mal gelesen, dass man bei ScriptLibs aufpassen muss, diese nicht mehrfach aufzurufen.
Als Tipp habe ich da u.a. gelesen, mann soll eine Globale Library erstellen ("GlobalLib"), und darin nur alle anderen Libs einbinden die man braucht in Masken etc. In Masken etc. schreibt man dann nur - Use "GlobalLib" - , was damit dann alles eingebunden wird, steuert man über die GlobalLib.

Ist das so praktikabel und sinnvoll? Da würde mich Eure Meinung zu interessieren.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: koehlerbv am 21.06.04 - 23:25:38
Das geht bei wenigen und kleinen Libs. Da sollte es aber auch keine Probleme geben, das "circular use" zu vermeiden.
Ich würde von diesem "Tipp" also die Finger lassen (meine persönliche Meinung). Solch eine GlobalLib pumpt immer allen Code beim Laden eines Designelements in dieses mit hinein.
Ich fahre m.E. erheblich besser, in dem ich die Libs entsprechend sinnvoll aufbaue, damit ich dann genau die Libs einbinden kann, die ich auch wirklich brauche. Diese versuche ich - wenn irgendwie machbar - so aufzubauen, dass es folgende Typen von ScriptLibs gibt:
- Basic (was man in jeder Applikation gebrauchen kann. So sparsam wie möglich aufgebaut, ggf. nochmals unterteilen !)
- Applikationsart-spezifisch (wenn es mehrere ähnliche Apps gibt)
- Applikationsspezifisch (wird nur in dieser App gebraucht)

Bernhard
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 21.06.04 - 23:30:05
Hört sich sinnvoll an, Bernhard.

Ich hatte ja bisher noch nie riesengroße Libs in meinen DB's. Aber wo ich wirklich warten musste (Sekundenbereich) beim öffnen eines Doks, war, als ich mit Normunds' RTLib experimentierte. Diese mächtige Lib sollte man wirklich mit Bedacht laden :-)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: koehlerbv am 21.06.04 - 23:37:38
Eben. Normunds Kalbernzins kann dagegen ja kaum was machen, und der Sinn der Lib erlaubt m.E. in der Regel auch lange Wartezeiten.
Aber unsereiner hat da viel mehr Möglichkeiten. Und die Aufteilung der Libs in sinnvolle, miteinander kooperierende Einheiten ist oft eine viel herausforderende Aufgabe als das Schreiben der Module selber. Und "eigentlich" sollte das "Gerüst" und seine Abhängigkeiten vor der ersten LOC feststehen. "Eigentlich"  ;D

Bernhard
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 22.06.04 - 07:07:44
Generelle Frage zu Klassen:

Angenommen ich habe eine Array-Script-Lib. Spricht was dagegen die dort verwendeten Subs und Functions in Klassen zu verwenden?
Klar - ich meine wenn man in der Array-Lib was gravierendes ändert (z.B. Rückgabewert einer Function plötzlich anderer Datentyp, etc.etc.) dann zerlegt es alles.

Ist mehr eine generelle Frage..... Ich denke ich werde in Klassen auch bewährte Functions verwenden. Und die würd ich dann auch nach wie vor zentral irgendwo vorhalten wollen.

in Java z.B. werden solche Funktionen in "Utility-Klassen" gehalten.
Da gibts z.B. die Klasse 'Math', die stellt Rechenfunktionen zur Verfügung.
Die Methoden der Klasse sind statisch (d.h. sie können aufgerufen werden, ohne ein Objekt der Klasse instantiieren zu müssen.) In LS gibt es keine statischen Methoden, deswegen ist es vermutlich geschickter, solche Hilfsfunktionen wie bisher als alleinstehende Funktionen in Scriptbibliotheken zu halten.

Für das Problem, wie man diese Bibliotheken strukturiert und welche Bibliotheken am besten welche anderen Bibliotheken nutzen, ohne ein "illegal circular use" zu erzeugen, habe ich leider kein Patentrezept. Wie man das macht, ist wohl von Anwendung zu Anwendung verschieden und hängt auch, wie Bernhard sagt, von der Anzahl der Bibliotheken ab.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: ata am 22.06.04 - 13:39:09
... generell gilt aber - nur laden, was auch tasächlich benötigt wird. Alles andere ist Ballast der auf die Performance drückt. Eher überlegen, wo ich den Code brauche...

... nur in einer einzigen Aktion oder in mehreren Aktion - entsprechend eben dann global oder lokal laden...

... oder den Code in Textdokumenten mit Lesezugriff verwalten und dann nur zur Ausführung laden und ausführen...

ata
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: Axel am 23.06.04 - 08:26:23
... oder den Code in Textdokumenten mit Lesezugriff verwalten und dann nur zur Ausführung laden und ausführen...


Hi,

so was suche ich schon länger. Kannst du mal erklären wie man so was macht.

Ich hab's mal versucht, bin aber immer gescheitert.


Axel
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: Markus Henke am 23.06.04 - 09:00:55
Ata, habe ich das richtig verstanden, dass Duu zum Teil Code in Dokumenten speicherst, anstatt ihn im Design zu haben? Das hört sich interessant an, was ist der Vorteil davon?

Markus
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: ata am 23.06.04 - 22:59:33
... das hat Vorteile, aber auch Nachteile...
Ich habe die Technik in meiner Support-Datenbank eingebaut. Damit lassen sich per Schlagwort dann verschiedene "Aktions-Bündel" zur Verfügung stellen.

Vorteile:
Mit normalen Notes-Mitteln kannst du bestimmen, wer den Code verändern kann, wer verwenden...
Mit einer kleinen Erweiterung eines Popup's kann man damit Aktionen an beliebiger Stelle zur Verfügung stellen. Einmal programmiert, an allen erreichbaren Stellen verwendbar...
Man kann auf ScriptLibraries der aktuellen Datenbank zugreifen.
Es lassen sich auch externe ".lss"-Dateien einbinden - damit keine 65K-Grenze...


Nachteile:
Als Entwicklerplattform bietet es zunächst keinerlei Komfort, da überlicherweise Notepad verwendet wird.
Dies lässt sich umgehen, wenn man die Dateien explicit auslagert und als ".lss" mit einem bestimmten Programm bearbeiten lässt. Hat dann aber die Nachteile, daß der Code vor Ort zur Verfügung stehen muss...
Debugging ist bei weitem nicht so komfortabel. Es kommt eine Fehlermeldung, die in der Regel hilfreich ist, wenn aber dein Code sehr umfangreich ist, dann solltest du einen Texteditor verwenden, der dir die Zeilennummer anzeigt, oder entsprechenden Debugging-Code einbauen...

@Axel:
Der Weg ist eigentlich ganz simpel:
Execute( |MsgBox("Hallole")| )

Das Geheimnis ist, das alle Objekte innerhalb des Execute's deklariert und initialisiert werden müssen. Wenn du etwas Geduld hast, dann zeig ich's in einer kleinen Demo-DB...

ata
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: ata am 24.06.04 - 00:05:41
... zur Demo reicht es heute nicht mehr - aber zu einer kleinen Anleitung:

Code
' # ###################################################
%REM
ata - 23.06.2004
In dieser kleinen Demo möchte ich zeigen, wie
Text als LS-Code ausgeführt werden kann.
Als Beispiel verwende ich 
... Globale Variablen
... Globale Funktionen
... normaler Code
'
Was für einen Wert gibt in diesem Beispiel die MsgBox zurück?
Die Rückgabe erscheint in der Statuszeile...
'
Man benötigt 
... ein Feld "Code"
... ein Event - zum Beispiel eine Schaltfläche
'
Als Schaltflächen-Code zur Ausführung dient:
'
Sub Click(Source As Button)
   Dim ws As New NotesUIWorkspace
   Dim docThis As NotesDocument
   Set docThis = ws.CurrentDocument.Document
   If docTHis.Code(0) <> "" Then
      vCode = docThis.Code
      sCode = ""
      For i = 0 To Ubound( docThis.Code )
         sCode = sCode + vCode( i ) + Chr(10)
      Next
      Execute( sCode )
   End If
End Sub
'
Das Feld "Code" ist ein Mehrfachwerte-Feld
... Mehrere Werte werden nur mit neuen Zeilen getrennt
%END REM
' # ###################################################
' # ... im Feld "Code" kann dann der folgende Code verwendet werden....
' 
' # Globale Deklarationen
Option Explicit
' Use "Deine LS-Library"
' %INCLUDE "C:\Temp\deineLSS-Datei.lss" ' lässt sich auch später noch einbauen...
Dim sPos As String
'
' ... dann lassen sich Klassen, Type's und Funktionen einbauen
Function makeMsg(  sText As String , iTyp As Integer ) As Integer
   sPos = "Sub makeMsg."
   On Error Goto ErrorHandle ' # innerhalb von Sub's und Function's sind Sprunmarken möglich
   makeMsg = MsgBox( "Ausgabe: " + sText , iTyp , "Ausgabe einer Meldung" )
Exit Function
'
ErrorHandle:
   Print "Fehler: " + sPos + Cstr( Erl )+ " - " + Error 
   Resume Next
End Function
'
' # ... letztendlich dann der eigentliche Code, der ausgeführt werden soll - hier sind keine Sprungmarken (GoTo) möglich...
Dim sText As String
Dim res As Integer
sText = "Hallole"
res = makeMsg( sText , 2  )
'
Print res

... der obige Code kann komplett in das Feld "Code" kopiert werden.
Mit der Schaltfläche wird dann der Code ausgeführt...

... es liese sich auch ein Rich-Text-Feld in der Maske plazieren, in der dann ein Button eingefügt wird. Als Code dient dann der "Click()"-Code aus dem Beispiel...

... und es gibt noch viel weitere Spielarten... ;D ;D ;D

ata
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: koehlerbv am 24.06.04 - 00:15:02
Danke, Anton, dass Du eine Lanze gebrochen hast für dieses hochwirksame LS-Statement. Das sollte eigentlich auch ein BP-Artikel wert sein ... Wir sollten das vielleicht im BP-Diskussionsforum weiter diskutieren.

Bernhard
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: ata am 24.06.04 - 00:17:16
... wenn du meinst...

Toni  ;D
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: Axel am 24.06.04 - 08:28:46
@ata

Danke für dein Beispiel. Das werde ich mal probieren.

Mit diesen Code-Feldern habe ich mich auch schon mal beschäftigt, bin aber auf keinen grünen Zweig gekommen.


Axel
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 24.06.04 - 23:16:56
Zwischenfrage, Thomas:

Wofür stehen eigentlich die Präfixe "m_" in Deinem Beispiel? Ist das nur so gewählt, oder hat das irgend einen Zweck?
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 25.06.04 - 08:31:38
Kennzeichnung für Membervariablen
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 25.06.04 - 20:41:02
Habe nun meine History komplett implementiert, allerdings in "nur" 3 Klassen:

(http://www.atnotes.de/attachments/historyclass_08.gif)


Dabei ist vorgesehen, dass man ein "HistoryEntry" auch so erzeugen kann.
Man setzt dann einfach die Property z.B. auf historyentry.Action = "Status auf 'In Progress' gesetzt" und führt dann ein Call historyentry.write(doc) aus.

Danke nochmal für Dein Beispiel, Thomas, das war sehr hilfreich.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 25.06.04 - 21:33:22
wo machst du denn jetzt die Unterscheidung zwischen RTF-History und Text-History?
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 25.06.04 - 21:44:57
RTF habe ich vorerst nicht eingebaut. In der jetzigen Lösung schreibe ich die Werte in 1 Textfeld (Liste).

Die Unterscheidung würde ich in der "HistoryMain" machen in der "Private Sub writeHistory()".


Das ist übrigens mein bisheriger Code-Draft der Klasse "HistoryEntry":
Code
Public Class HistoryEntry
   Private m_itmHistory As NotesItem
   Private m_vAction As Variant
   Private m_strHistoryEntry As String
   '------------------------------------------------------------------------------------------------   
   Public Sub new()
      
   End Sub
   '------------------------------------------------------------------------------------------------   
   'Get/Set-Methoden
   Public Property Set Action As Variant
      m_vAction = Action   
   End Property
   '------------------------------------------------------------------------------------------------   
   Public Sub write(doc As NotesDocument)
        'neuen History - Eintrag schreiben
      Call assembleHistory()
      Set m_itmHistory = doc.GetFirstItem("History")
      Call m_itmHistory.AppendToTextList( m_strHistoryEntry )
'      Call doc.Save(True, True)
   End Sub
   '------------------------------------------------------------------------------------------------   
   Private Sub assembleHistory()
      'History zusammenstellen
   'Output ist in m_strHistoryEntry
      Dim session As New notessession
      Dim strName As String
      Dim strDate As String
      Dim i As Integer
      strName = session.CommonUsername
      strDate = Format$( Now , "dd.mm.yyyy hh:mm")
      
      For i = 0 To Ubound(m_vAction)
         If i=0 Then
            m_strHistoryEntry = strDate & Chr(9) & strName & Chr(9) & m_vAction(i)
         Else
            m_strHistoryEntry = m_strHistoryEntry & Chr(13)+Chr(10) & Chr(9) & Chr(9) & m_vAction(i)
         End If
      Next
      
   End Sub
   '------------------------------------------------------------------------------------------------   
   
End Class

Was aber nicht heißen soll, dass Deine Aufteilung nicht gut ist - war mir nur als Anfänger etwas zu kompliziert.

Was hier in der HistoryEntry - Klasse imho u.a. noch nicht perfekt ist:
 - Datumsformat ist statisch
 - Username ist statisch (vielleicht brauche ich mal ein anderes Format)
 - Prüfung wieviele History-Zeilen existieren ist noch nicht eingebaut.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 25.06.04 - 21:58:14
Noch 'ne Frage:

Gibt's eigentlich spezielle Regeln  und Tipps für ErrorHandling in Klassen?

Oder macht man das "ganz normal" wie üblich in Functions und Subroutinen:
Wo man direkt eingreifen kann z.B. mit "If.....Then" abfangen, ansonsten am Anfang ein "On Error goto ErrorHandler"?
Wo habt Ihr den Code für die Fehlerabarbeitung? In den jeweiligen Klassen selber oder in einer eigenen Function/Sub, die Ihr von der Klasse aus aufruft?

Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 25.06.04 - 23:08:09
ich kenne keine speziellen Regeln.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: Marinero Atlántico am 26.06.04 - 12:12:22
Das mit dem ErrorHandling ist ein guter Punkt.

@Thomas: Verate uns ungewaschenen Massen den Trick, wie man in HistoryEntry die Factory implementiert , um das Strategy-Pattern für die Subklassen zu implementieren.
oder schickt mir eine nsf, wenn es für euer Zeugs bisher eine Implementierung aka Beispieldatenbank gibt.

Gruß Axel
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 26.06.04 - 12:40:31
der Code und die Diagramme, die ich hier gepostet habe, sind von mir schnell zusammengezimmert worden. TMC hat das in eine DB gepackt und hier in den Thread gehängt.

Ich verwende kein Strategy und auch kein Factory-Pattern.

Wie TMC das jetzt gemacht hat, weiß ich nicht genau.
In meinem Fall war HistoryEntry abstrakt. Die Subklassen hatten spezielles Wissen darüber, wie sie die Informationen ins NotesDokuemnt schreiben müssen.
Als 'Factory' musste die History-Klasse selbst herhalten, die z.B. anhand eines Wertes/Feldes im betroffenen Dokument entscheidet, welches spezielle HistoryEntry-Objekt sie erstellt.

Wir können das sehr gerne weiter ausbauen. Mein Lösungsvorschlag ist vermutlich noch far from perfect und erhebt keinerlei Anspruch darauf, als Referenz herzuhalten.
Sowas ist vielleicht sogar ein interessantes Projekt für hier, weil zeitlich sehr überschaubar und evtl. von großem allgemeinem Nutzen.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 26.06.04 - 12:56:02
ah, ok. dieses HistoryEntry-Konstrukt kann man tatsächlich als Strategy sehen. War nicht bewusst von mir. Aber Factory hab ich keine. Das übernimmt die History-Klasse selbst
Aber ich bin echt auf Ideen gespannt, wie man das besser machen kann :D
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 26.06.04 - 13:40:40
Man gebe mir etwas Zeit, dann poste ich denn kompletten Sourcecode meiner bisherigen Umsetzung.  ;)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: Marinero Atlántico am 26.06.04 - 14:46:09
Als 'Factory' musste die History-Klasse selbst herhalten, die z.B. anhand eines Wertes/Feldes im betroffenen Dokument entscheidet, welches spezielle HistoryEntry-Objekt sie erstellt.

Genau das habe ich gemeint. Warum Factory in Anführungszeichen. Für mich ist das eine Factory. Oder warum soll sie das nicht sein?

Das Geheimnis von Design Patterns ist, dass sie eigentlich nicht so geheimnisvoll sind und man schnell selber draufkommt. Wenn man sie kennt, hat man die Möglichkeit einer gemeinsamen Meta-Sprache.

Ich versuch das manchmal im Büro, wenn ich den code von jemand anders übernehme, beim Gespräch alles in Design Patterns auszudrücken. Zur Übung. Die sagen immer: "Axel, hör auf".  ;D
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 26.06.04 - 14:58:39
Genau das habe ich gemeint. Warum Factory in Anführungszeichen. Für mich ist das eine Factory. Oder warum soll sie das nicht sein?

naja, unter einer Factory verstehe ich halt eine Klasse, deren einzige Aufgabe es ist, Objekte rauszurücken.
Und die Klasse History hat in diesem Fall zusätzliche Aufgaben. Objekte zu erzeugen ist nur eine Nebenaufgabe.

Irgendwie gefällt mir diese Klasse sowieso nicht, so wie sie jetzt ist...
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 26.06.04 - 15:06:26
solch eine Factory-Klasse habe ich übrigens absichtlich erstmal rausgelassen.
es kamen ja schon Gegenstimmen, als ich vorschlug, mehrere Klassen zu verwenden für diese Geschichte. Da wollte ich es für den Anfang mal etwas langsam angehen lassen. :D
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 26.06.04 - 15:11:42
RTF habe ich vorerst nicht eingebaut. In der jetzigen Lösung schreibe ich die Werte in 1 Textfeld (Liste).

Die Unterscheidung würde ich in der "HistoryMain" machen in der "Private Sub writeHistory()".

ich habe mich falsch ausgedrückt.
wenn du da jetzt zusätzlich noch RTF-Histories schreiben willst - wo wirst du den zusätzlichen Programmcode hinschreiben?
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 26.06.04 - 15:19:26
Das Geheimnis von Design Patterns ist, dass sie eigentlich nicht so geheimnisvoll sind und man schnell selber draufkommt. Wenn man sie kennt, hat man die Möglichkeit einer gemeinsamen Meta-Sprache.

Da hast du recht. Das Problem ist, dass diese Sprache hier schätzungsweise 97% nicht sprechen.
Aber natürlich ist es auch schwierig darüber zu diskutieren, ohne die Sprache zu kennen (ich hab gerade mal versucht, deinen Satz
Zitat
wie man in HistoryEntry die Factory implementiert , um das Strategy-Pattern für die Subklassen zu implementieren
in neutraler Sprache zu formulieren - geht natürlich nicht.

Ich versuche, langsam vorzugehen... :D
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 26.06.04 - 15:55:44
OK, wie versprochen hier meine bisherige Umsetzung:

history_01.nsf (320KB) (http://217.160.137.156/user/bp/tmc/_threaduploads/history/history_01.nsf)

Kann sich das hier u.a. bitte mal wer anschauen:
(http://217.160.137.156/user/bp/tmc/_threaduploads/history/historyclass_09.gif)

Weiß nicht; ist das noch objektorientiert, oder unsauber, diese Scripts auszulagern aus der Klasse?


Ach ja, noch kurze Erklärung zum Aufbau der angehängten DB:
* Das History-Feld ist in einer Teilmaske. Dort arbeite ich mit 2 Feldern. Grund: wegen Mehrfachwerten und Zeilenumbruch, sonst bringe ich die Darstellung nicht sauber hin.
* Die zu überwachenden Felder werden hier in den Global Declarations der Maske "MyForm01" definiert
* Anzahl History-Einträge wird noch nicht überwacht, muss ich noch einbauen

Bugs (gerade entdeckt - 16:09 Uhr):
- Wird das Dok nur gespeichert, aber nicht geschlossen, dann werden die InitialValues nicht aktualisiert.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 26.06.04 - 15:57:28
RTF habe ich vorerst nicht eingebaut. In der jetzigen Lösung schreibe ich die Werte in 1 Textfeld (Liste).

Die Unterscheidung würde ich in der "HistoryMain" machen in der "Private Sub writeHistory()".

ich habe mich falsch ausgedrückt.
wenn du da jetzt zusätzlich noch RTF-Histories schreiben willst - wo wirst du den zusätzlichen Programmcode hinschreiben?

Hmm, ich würde wohl die HistoryEntry - Klasse duplizieren und anpassen ("HistoryEntryRTF") oder so.....
Perfekt ist das wohl allerdings nicht...
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: eknori am 26.06.04 - 16:21:45
schöne Arbeit  :D

kleiner Bug:

Wird ein Document erstellt und über die "Diskette" gespeichert und anschließend über Speichern und schließen verlassen, gibt es zwei Einträge über die Neuanlage
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 26.06.04 - 16:25:23
Danke, Ulrich.

Wobei: es sind wohl erst gute 50% fertig, viele Feinarbeiten sind noch zu tun und noch ein paar Dinge zu implementieren.

Zum Bug:
Hatte ich vorhin auch gerade entdeckt  ;) (siehe Anmerkung in Antwort 77).
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 26.06.04 - 16:50:50
Nochmal zu diesem Bug (Initial-Values werden nicht neu gesetzt nach dem Speichern):

Man könnte den beheben in dem man einfach das History-Objekt neu erstellt beim PostSave in der HistoryMonitorDoc-Klasse:
(http://217.160.137.156/user/bp/tmc/_threaduploads/history/historyclass_10.gif)

Ist imho aber nicht sauber.

Hmm, alternativ könnte man die "Private Sub readInitialValues()" der HistoryMain - Klasse aufmachen und zu Public machen, und dann in der HistoryMonitorDoc - Klasse dann folgendes machen:

 Private Sub ProcessPostSave(Source As NotesUIDocument)
         'nach dem Speichern des Dokuments muss die History geschrieben werden
      Call m_History.save()
      'Nun müssen die neuen Werte wieder gesetzt werden.
      Call m_History.ReadInitialValues()
   End Sub
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 26.06.04 - 16:57:15
funktioniert ;D

zu den Hilfsfunktionen:
Explode und ErrorHandler sind Kandidaten für eine 'Hilfsfunktions-Bibliothek'

die anderen haben alle was mit Feldern zu tun (gib mir Werte, zeig mir Unterschiede, ...) damit haben wir einen neuen Kandidaten für eine Klasse 'Feld'. die all diese Funktionalität zur Verfügung stellt.

Eine Frage jenseits von OO:
welchen Grund hat es, dass du die Namen der Felder, die überwacht werden sollen, in einem String hältst und nicht in einer Liste/Array/...?
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 26.06.04 - 17:00:10
Nochmal zu diesem Bug (Initial-Values werden nicht neu gesetzt nach dem Speichern):

Man könnte den beheben in dem man einfach das History-Objekt neu erstellt beim PostSave in der HistoryMonitorDoc-Klasse:
(http://)

Ist imho aber nicht sauber.

Hmm, alternativ könnte man die "Private Sub readInitialValues()" der HistoryMain - Klasse aufmachen und zu Public machen, und dann in der HistoryMonitorDoc - Klasse dann folgendes machen:

 Private Sub ProcessPostSave(Source As NotesUIDocument)
         'nach dem Speichern des Dokuments muss die History geschrieben werden
      Call m_History.save()
      'Nun müssen die neuen Werte wieder gesetzt werden.
      Call m_History.ReadInitialValues()
   End Sub


du hast die neuen Werte ja schon. du müsstest nur sowas hier in deiner History-Klasse machen, nachdem der Eintrag gemacht wurde:

m_vaInitialFieldValues = m_SavedFieldValues
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 26.06.04 - 17:09:27
zu den Hilfsfunktionen:
Explode und ErrorHandler sind Kandidaten für eine 'Hilfsfunktions-Bibliothek'
Hmm, stimmt. Ziel ist allerdings für mich hier, die Klassen per Copy'n'Paste in beliebigen DB's einzusetzen (auch wenn diese sonst keine Klassen haben). Aber vielleicht macht man da dann einfach eine "HistoryHilfsfunktionen" - Lib, die dann immer mitkopiert wird... ?!

die anderen haben alle was mit Feldern zu tun (gib mir Werte, zeig mir Unterschiede, ...) damit haben wir einen neuen Kandidaten für eine Klasse 'Feld'. die all diese Funktionalität zur Verfügung stellt.
Ah ja..... gute Idee :-)

Eine Frage jenseits von OO:
welchen Grund hat es, dass du die Namen der Felder, die überwacht werden sollen, in einem String hältst und nicht in einer Liste/Array/...?
In Konstanten (hier: Global Declarations der Maske) sind leider Arrays nicht möglich afaik. Daher schreibe ich die dort in ein String mit Trennzeichen "##", übergebe diese dann an das Objekt "HistoryMonitorDoc", von da aus weiter an das "HistoryMain"-Objekt und im HistoryMain-Objekt wandle ich die dann in ein Array um (mittels der ExtExplode - Function):
Code
   Private Sub getHistoryFields(strNames As String, strTitles As String)
      'die zu prüfenden Felder ermitteln
      m_vaHistoryFields = ExtExplode(strNames, "##")
      m_vaHistoryFieldTitles = ExtExplode(strTitles, "##")

Bin da aber aufgeschlossen, wenn Du 'ne bessere Idee zur Umsetzung hast :-)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 26.06.04 - 17:18:11
Nochmal zu diesem Bug (Initial-Values werden nicht neu gesetzt nach dem Speichern):
(....)

du hast die neuen Werte ja schon. du müsstest nur sowas hier in deiner History-Klasse machen, nachdem der Eintrag gemacht wurde:

m_vaInitialFieldValues = m_SavedFieldValues

Jo mei, Du hast natürlich Recht, so geht's:
Code
   Private Sub writeHistory()
     'Werte vergleichen und Ergebnisse an den HistoryEntry geben
      m_HistoryEntry.Action = m_vDifferences
      'History-Eintrag ins Dokument schreiben
      Call m_HistoryEntry.write(m_doc)
      'Neue Werte in das InitialValue-Array schreiben, für den Fall dass erneut gespeichert wird
      m_vaInitialFieldValues = m_SavedFieldValues
   End Sub
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 26.06.04 - 17:21:43
In Konstanten (hier: Global Declarations der Maske) sind leider Arrays nicht möglich afaik. Daher schreibe ich die dort in ein String mit Trennzeichen "##", übergebe diese dann an das Objekt "HistoryMonitorDoc", von da aus weiter an das "HistoryMain"-Objekt und im HistoryMain-Objekt wandle ich die dann in ein Array um (mittels der ExtExplode - Function):
Code
   Private Sub getHistoryFields(strNames As String, strTitles As String)
      'die zu prüfenden Felder ermitteln
      m_vaHistoryFields = ExtExplode(strNames, "##")
      m_vaHistoryFieldTitles = ExtExplode(strTitles, "##")

Bin da aber aufgeschlossen, wenn Du 'ne bessere Idee zur Umsetzung hast :-)

naja, die Frage ist, ob wir hier Konstanten einsetzen müssen.
Ich sehe das so: String-Konstanten setze ich ein, wenn ich die Zeichenfolge, die sie darstellen, an 1-n Stellen verwenden müsste. So vermeide ich Tippfehler und ich kann einen Wert an einer Stelle ändern und das hat Auswirkungen auf alle Stellen, wo dieser Wert verwendet wird.

In diesem Fall käme in meinen Augen die "Befüllung" einer Liste mit den Feldnamen der Deklaration einer Konstanten gleich. (Und ich würde mir damit das hantieren mit irgendwelchen Trennzeichen sparen :) )
Aber das ist Geschmackssache.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 26.06.04 - 17:31:24
naja, die Frage ist, ob wir hier Konstanten einsetzen müssen.
Ich sehe das so: String-Konstanten setze ich ein, wenn ich die Zeichenfolge, die sie darstellen, an 1-n Stellen verwenden müsste. So vermeide ich Tippfehler und ich kann einen Wert an einer Stelle ändern und das hat Auswirkungen auf alle Stellen, wo dieser Wert verwendet wird.

In diesem Fall käme in meinen Augen die "Befüllung" einer Liste mit den Feldnamen der Deklaration einer Konstanten gleich. (Und ich würde mir damit das hantieren mit irgendwelchen Trennzeichen sparen :) )
Aber das ist Geschmackssache.

An welchem Ort würdest Du das denn machen? Im Postopen der Maske?

Ich habe ja auch schon hin- und herüberlegt......

Auf die History-Klasse(n) wird man wohl dann von mehreren Seiten zugreifen
A) Wie hier umgesetzt über Postopen der Maske
B) Beispielsweise in einer Workflow-Anwendung, wo man dann z.B. eine Statusänderung reinschreibt wie "Approved document." oder so.

Problem: Wo lege ich z.B. zentral fest, wie viele Einträge die History überhaupt haben darf?
Entweder macht man das imho in der Klasse - oder aber via Setup-Dokument. Welches sich ja auch für die Definition der zu überarbeitenden Feldern anbieten würde.

Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 26.06.04 - 17:44:08
Nochmal zum Errorhandling:

Hab grad sowas versucht:

Code
Public Class HistoryMain
   
   On Error goto ErrorHandler

Dann kommt die Meldung:
Zitat
HistoryMain: (Declarations): 10: Statement illegal in CLASS block: ON

Heißt das man müsste das Errorhandling in jede Sub/Function der Klasse einzeln schreiben?
Schade....
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 26.06.04 - 17:48:39
ja, also Setup/Konfigurationsdokument ist immer mein Favorit.
Dann kann da schrauben, ohne an den Code zu müssen.

Wenn ich es im Code machen würde, dann würde ich es in der Maske machen. Wo da genau ist wohl auch Geschmackssache
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 26.06.04 - 19:21:31
Hier nun eine neue Version.

Bugs entfernt:
+ o.g. Bug entfernt
+ CStr() eingebaut, damit sollten nun auch Datumsfelder etc. überwachbar sein :-)

Neu:
+ Klasse "HistoryField"
+ ScriptLib "HistoryAuxiliaryRoutines"

Download:
history_02.zip (35 KB) (http://217.160.137.156/user/bp/tmc/_threaduploads/history/history_02.zip)


Kann sich da bitte mal wer die Klasse "HistoryField" anschauen?
Passt die so?



Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 26.06.04 - 19:58:56
ich habe Anmerkung zu der neuen Klasse.

Was du gemacht hast ist, vereinfacht ausgedrückt, die Funktionen gepackt, in eine Bibliothek gepackt und 'Class' drum herum geschrieben.

Das ist nix Schlimmes, nur ist das nicht so ganz das, was ich mir vorgestellt habe, als ich schrieb, wir brauchen eine Feld-Klasse, und das ist ja auch nicht schlimm.

Da wir hier aber in einem Thread sind, in dem es darum geht, wie man geschickt objektorientiert analysiert, entwirft und programmiert, versuche ich zu erklären, was ich beim Schreiben im Kopf hatte.
Ein Objekt der Klasse 'Feld' repräsentiert genau ein zu überwachendes Feld aus dem Notesdokument. D.h., wenn ich drei Felder überwachen will, dann brauche ich drei Objekte. Jedes Objekt kann mir Auskunft darüber geben, welchen Wert 'sein' Feld hat, welchen es ürsprünglich hatte bzw. worin der Unterschied zwischen den beiden Werten besteht.
Unser History-Objekt müsste alle Feld-Objekte instanziieren und würde so alle kennen. Wenns dann zum schreiben der Änderungen geht, frägt das History-Objekt der Reihe nach seine Feld-Objekte nach ihren Änderungen und gibt die Ergebnisse an das HistoryEntry-Objekt oder evtl. noch besser, sie übergibt die Feld-Objekte an das History-Entry-Objekt und das fragt selbst nach.

Wir könnten hier das gleiche Prinzip anwenden, wie ich bei der HistoryEntry-Klasse vorgeschlagen habe, also eine abstrakte Basisklasse 'Feld' und davon abgeleitete Klassen 'Textfeld' und 'RTFFeld'
(ich hab da in deinem Code irgendwas mit "I AM RTF" gesehen, ich weiß zwar nicht genau, wofür das ist, aber evtl. könnte man sowas durch solche Subklassen umgehen...)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 26.06.04 - 20:02:19
ist der Unterschied zwischen den beiden Varianten klar? Wenn nicht, dann einfach nachfragen
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 26.06.04 - 20:22:01
Was du gemacht hast ist, vereinfacht ausgedrückt, die Funktionen gepackt, in eine Bibliothek gepackt und 'Class' drum herum geschrieben.
Stimmt, genau das habe ich gemacht  ;D

Ein Objekt der Klasse 'Feld' repräsentiert genau ein zu überwachendes Feld aus dem Notesdokument. D.h., wenn ich drei Felder überwachen will, dann brauche ich drei Objekte. Jedes Objekt kann mir Auskunft darüber geben, welchen Wert 'sein' Feld hat, welchen es ürsprünglich hatte bzw. worin der Unterschied zwischen den beiden Werten besteht.
Unser History-Objekt müsste alle Feld-Objekte instanziieren und würde so alle kennen. Wenns dann zum schreiben der Änderungen geht, frägt das History-Objekt der Reihe nach seine Feld-Objekte nach ihren Änderungen und gibt die Ergebnisse an das HistoryEntry-Objekt oder evtl. noch besser, sie übergibt die Feld-Objekte an das History-Entry-Objekt und das fragt selbst nach.
Das habe ich glaub ich soweit verstanden. Klingt auch sehr sinnvoll und praktikabel.

Wie würdest Du denn die Feld-Objekte erzeugen? Über eine Schleife? Das ist mir noch nicht ganz klar. Man kann ja z.B. nur 1 Feld zur Überwachung haben oder vielleicht auch 100 (worst case).

Wir könnten hier das gleiche Prinzip anwenden, wie ich bei der HistoryEntry-Klasse vorgeschlagen habe, also eine abstrakte Basisklasse 'Feld' und davon abgeleitete Klassen 'Textfeld' und 'RTFFeld'
(ich hab da in deinem Code irgendwas mit "I AM RTF" gesehen, ich weiß zwar nicht genau, wofür das ist, aber evtl. könnte man sowas durch solche Subklassen umgehen...)

Das "I_AM_RTF" ist bisher so ein Workaround. Wenn das Feld vom Typ RTF ist, dann wird "I_AM_RTF" + Änderungsdatum in ein Array geschrieben; wenn nicht RTF, dann eben der Feldinhalt. Dadurch wird dann beim Zusammensetzen des Actions-Textes erkennbar, was man dort reinschreibt ("Changed RTF...." oder "Changed Field.... former value was ....")


Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 26.06.04 - 20:31:43
Klar, in einer Schleife. Im Konstruktor der History-Klasse.
Da, wo jetzt das steht

      If m_strTextNew = "" Then 'Nur wenn es sich nicht um ein neues Doc handelt
         Call getHistoryFields(m_strHistoryFieldNames, m_strHistoryFieldTitles)
         Call readInitialValues()
      End If

Möglichkeit:
du übergibst dem Konstruktor die Liste mit den Feldnamen und der Konstruktor ruft dann eine Methode zum Erzeugen der Field-Objekte auf (oder machts selber, musst mal schaun)
Die Objekte würden dann die beiden Arrays (Initial und SavedValues) ersetzen.

Was mir gerade einfällt:
Ähnlich wie dein Dokument-Objekt eine Assoziation zum entsprechenden NotesUIDocument-Objekt hat (m_uidoc) könnte jedes Feld-Objekt eine Assoziation zum entsprechenden NotesItem-Objekt haben
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 26.06.04 - 20:41:07
OK danke, in der Theorie hab ich das soweit kapiert, mal sehen ob ich das auch so umsetzen kann.  ;)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 26.06.04 - 23:51:41
@Thomas: Verate uns ungewaschenen Massen den Trick, wie man in HistoryEntry die Factory implementiert , um das Strategy-Pattern für die Subklassen zu implementieren.
oder schickt mir eine nsf, wenn es für euer Zeugs bisher eine Implementierung aka Beispieldatenbank gibt.

ist die Frage eigentlich noch offen?
ich weiß nicht genau, was du mit 'Trick' meinst, Axel.
Da ist kein Trick. In dem Beispielcode, den ich gepostet habe, habe ich völlig offen gelassen, wie entschieden wird, welches spezielle Objekt erzeugt wird. Möglichkeiten sind z.B. Felder/Feldwerte im betroffenen Dokument, irgendwelche Konfigurationsdokumente, etc.

Frag einfach nochmal, wenn ich die Frage nicht zufriedenstellend beantwortet habe.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 26.06.04 - 23:58:00
Ich bin übrigens gerade dabei, eine Logik einzubauen, um diese blöde Textfeld-Größenbeschränkung zu überwachen.
Nicht dass wer meint ich wäre mittlerweile eingeschlafen :-) (na ja, im Rahmen von MultiTasking mach ich auch nebenbei noch andere Dinge, hab ja auch parallel noch die Book-Rezension gemacht :))

Code
   Private Sub removeEntries()
      'Ziel ist es die Größenbeschränkung von Textfeldern zu beachten.
      'Zusätzlich kann der History-Klasse eine Max-Anzahl Einträge übergeben werden.
      'Wenn Max-Anzahl = "", dann wird gleich die Größenüberprüfung eingeleitet.
      'Wenn Max-Anzahl vorgegeben, dann wird erst mal gekürzt und der neue Wert
      'angehängt. Wenn immer noch zu lang: Solange alte Einträge rauswerfen, bis es passt.

While-Wend Schleifen, eine "DeleteArrayPosition"-Function etc. sind dabei hilfreich....
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 27.06.04 - 00:49:59
ich habs bis jetzt weggelassen, weil ich nicht übertreiben wollte und weils auch nicht nötig war. An dieser Stelle passt es vielleicht.

wir haben ja von History zu HistoryEntry eine 1:n - Beziehung, d.h. zu einem History-Objekt können mehrere HistoryEntry-Objekte gehören.

Im Code würde das so aussehen (in der Klasse History):

Private m_HistoryEntries() As HistoryEntry

also hätten wir ein Array voll mit Objekten anstelle des einen Objekts, das wir jetzt haben.
Denkbar wäre zur Lösung deines Problems folgendes zu tun:
Ein HistoryEntry-Objekt kennt die Größe seines Texts im Notesdokument und  stellt diese Information auch anderen Objekten zur Verfügung (über get-Methode)
Im Konstruktor des History-Objekts (oder in einer Methode, die von dort aus aufgerufen wird) erzeugen wir für jeden Eintrag im Dokument ein HistoryEntry-Objekt und fügen es unserem Array (m_HistoryEntries, s. oben) hinzu.
Beim Speichern des Dokuments wird wie bisher ein HistoryEntry-Objekt erzeugt, das die aktuellen Änderungen repräsentiert und dem Array hinzugefügt.
Wir haben jetzt also alle HistoryEntry-Objekte in unserem Array, und können bevor wir sie ins Dokument schreiben jedes HistoryEntry-Objekt fragen, wie groß es ist, und mit dieser Information entscheiden, wie viele Einträge wir machen.

Nur ne Idee. Einigermaßen verständlich?
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 27.06.04 - 01:21:02
Nur ne Idee. Einigermaßen verständlich?

Leider nicht ganz.
Liegt wohl auch an meinem etwas anderen Ansatz.

Hab mir das so gedacht:
Völlig egal ist erstmal, wieviele Zeilen im History-Feld aktuell sind. Jedenfalls passiert irgendwas (User klickt einen Workflow-Button an, oder User öffnet das Dok und will es nach Änderungen speichern) - dadurch wird ein HistoryEntry - Objekt erstellt. Dem Objekt werden dann die Änderungen übergeben (hier als Property), z.B. "habe Antrag genehmigt" oder aber "Feld ABC geändert; alter Wert war "bla bla"". Die Klasse managed den Rest: Wird durch das Ergänzen der neuen Zeile irgend ein Limit überschritten, dann werfen wir den ersten Eintrag raus. Immer noch überschritten: dann fliegt auch der nächste Eintrag raus. While...wend.
Na ja, wie auch immer, habe dank While...wend hier gerade eine Endlosschleife die ich noch flicken muss  :P ;D

Ich sehe jetzt nicht ganz die Erfordernis das noch zu splitten. Aber es ist auch schon spät. Kann sein dass ich das erst nach ein paar Stunden Schlaf kapiere...
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 27.06.04 - 01:33:01
Im Konstruktor des History-Objekts (oder in einer Methode, die von dort aus aufgerufen wird) erzeugen wir für jeden Eintrag im Dokument ein HistoryEntry-Objekt und fügen es unserem Array (m_HistoryEntries, s. oben) hinzu.

Meinst Du damit, dass pro Feld-Änderung ein HistoryEntry-Objekt erzeugt wird? Also: Feld1 hat sich geändert -> wir machen ein neues HistoryEntry-Objekt auf, Feld2 hat sich geändert -> wir machen ein weiteres neues HistoryEntry-Objekt auf usw. ?
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 27.06.04 - 01:35:00
nein. pro Eintrag.
Ein Eintrag enthält alle Änderungen eines Speichervorgangs.
wenn deine Einträge einzeilig wären, könnte man sagen ein Objekt pro Zeile
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 27.06.04 - 01:36:51
das heißt, du liest beim Öffnen des Dokuments erstmal alle History-Einträge aus (musst du ja sowieso machen, um die Größe zu bestimmen).
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 27.06.04 - 01:43:23
Danke, hab ich nun soweit verstanden.

Das hier bestätigt es auch:
Wir haben jetzt also alle HistoryEntry-Objekte in unserem Array, und können bevor wir sie ins Dokument schreiben jedes HistoryEntry-Objekt fragen, wie groß es ist, und mit dieser Information entscheiden, wie viele Einträge wir machen.

Blöde Frage: Was bringt es, alle Einträge separat in einem Objekt zu haben? Oder anders herum: Ist das eleganter, als wie wenn man das komplette Array (also ein String-Array mit den History-Einträgen) als ganzes behandelt?
Ich sehe da noch nicht ganz den Vorteil.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 27.06.04 - 01:53:37
Nur ne Idee. Einigermaßen verständlich?

Leider nicht ganz.
Liegt wohl auch an meinem etwas anderen Ansatz.

Also wie gesagt, im Konstruktor der History lesen wir die bisherigen History-Einträge im Dokument aus und erstellen für jeden Eintrag ein HistoryEntry-Objekt. Alle HistoryEntry-Objekte wandern in ein Array/Liste/...
Die Liste ist Attribut der History (Membervariable)

Zu dieser Liste kommt noch der HistoryEntry für die aktuelle Änderung.

Ein Dokument wurde bis jetzt dreimal gespeichert und gerade wurde es zum vierten Mal gespeichert, ergo haben wir vier HistoryEntry-Objekte.

O1 vom 10.06.
O2 vom 12.06.
O3 vom 17.06.
O4 vom 25.06.

So, nun müssen wir die History im Notesdokument aktualisieren und dabei aufpassen, dass wir nicht zuviel Text schreiben.
Die max. Größe ist unserem History-Objekt bekannt.
Ebenfalls kennt dieses Objekt alle HistoryEntry-Objkete, die ins Dokument müssen.

Mein Gedanke ist nun, dass das HistoryObjekt nacheinander jedes HistoryEntry-Objekt fragt, wie groß es ist und zwar solange, bis die Gesamtgröße überschritten wurde oder eben kein Objekt mehr zum Fragen da ist.

Also:
Größe max = 15k

O4, wie groß bist du? - 4k -> Summe 4, OK
O3, wie groß bist du? - 4k -> Summe 8, OK
O2, wie groß bist du? - 4k -> Summe 12, OK
O1, wie groß bist du? - 4k -> Summe 16, mööp

O2, schreib dich ins Dokument
O3, schreib dich ins Dokument
O4, schreib dich ins Dokument


oder zumindest so ähnlich.
etwas klarer?
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 27.06.04 - 02:10:08
Danke für die Ausführung, Thomas.

Nun habe auch ich das verstanden   :P :D

Die Vorgehensweise klingt sehr vernünftig. So vermeidest Du auch Endlos-Schleifen (wie ich z.B. vorhin erzeugt habe).

Frage: Würde das nicht auch via eine normale Function realisierbar sein?
Also sowas wie
Function Irgendwas (vInput, iMax) as Variant
Den Rückgabewert würde ich da dann ins History-Item setzen.

Soll jetzt wirklich nicht negativ klingen. Als Übung werde ich versuchen das so via Objekte umzusetzen (ich will ja OO lernen), aber mir macht es den Anschein, dass da eine Function hier einfacher wäre.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 27.06.04 - 02:23:02
Was bringt es, alle Einträge separat in einem Objekt zu haben? Oder anders herum: Ist das eleganter, als wie wenn man das komplette Array (also ein String-Array mit den History-Einträgen) als ganzes behandelt?
Ich sehe da noch nicht ganz den Vorteil.

Eleganter ist es vielleicht, aber vor allem ist es objektorientiert, und genau das wollen wir hier üben, wenn ich das richtig verstanden habe.
 ;D

Im Ernst, einen direkt messbaren Vorteil kann ich dir für diesen Fall nicht nennen. Ich vermute, dass du einen Vorteil hast, wenn sich mal was an den Anforderungen an deine History ändert, das diese Stelle betrifft (mir fällt grade keine gescheite Änderung ein). Kann natürlich sein, dass der Fall nie eintritt.

Ich persönlich finde es auf die Art, die ich beschrieben habe einfacher und leichter verständlich.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 27.06.04 - 02:28:03
OK  :)
Wie auch immer, ich werde auf jeden Fall Deinen Weg gehen - alleine schon weil es eine gute Übung für mich ist  ;)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 27.06.04 - 02:31:26

Frage: Würde das nicht auch via eine normale Function realisierbar sein?
Also sowas wie
Function Irgendwas (vInput, iMax) as Variant
Den Rückgabewert würde ich da dann ins History-Item setzen.

klar, warum nicht?!


Soll jetzt wirklich nicht negativ klingen. Als Übung werde ich versuchen das so via Objekte umzusetzen (ich will ja OO lernen), aber mir macht es den Anschein, dass da eine Function hier einfacher wäre.

Kein Problem. Das mit dem 'einfacher' ist halt so eine Sache.
Für dich ist es einfacher, das auf die Art zu lösen, die du bis jetzt immer benutzt hast. Wen wundert das?
Für mich ist es einfacher, das etwas anders anzugehen. Und es macht mir verdammt viel Spaß :)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 27.06.04 - 02:41:41
Zitat
Für dich ist es einfacher, dass auf die Art zu lösen, die du bis jetzt immer benutzt hast. Wen wundert das?
;D

Da passt der Spruch "Was der Bauer nicht kennt, das isst er nicht".

Ich habe ja oben schon geschrieben dass ich OO lernen will - und das war ja auch der Auslöser dieses Threads. Erst wenn ich das drauf habe (und das wird wohl bestimmt nicht von heute auf morgen sein) steht es mir imho zu, über Pro/Contra hierüber zu diskutieren  :)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: Marinero Atlántico am 27.06.04 - 10:34:27
Hi,

Total offtopic:
trotz anders angekündigt, komme ich später zum code zurück.
Das ganze hier finde ich ziemlich interessant. Ich mache nur am Mittwoch meine letzte Websphere certi und WAS gibt mir momentan eine harte Zeit mit zahlreichen kleinlichen ErrorMeldungen, wie
Code
In der JMSConnection für MDB SampleMDB, JMSDestination jms/sampleQ ist ein Fehler aufgetreten: javax.jms.JMSException: MQJMS2008: Fehler beim Öffnen der MQ-Warteschlange.  
>:(
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 27.06.04 - 17:01:43
Hab mir das jetzt so überlegt:

(http://217.160.137.156/user/bp/tmc/_threaduploads/history/historyclass_11.gif)


Im Konstruktor des History-Objekts (oder in einer Methode, die von dort aus aufgerufen wird) erzeugen wir für jeden Eintrag im Dokument ein HistoryEntry-Objekt und fügen es unserem Array (m_HistoryEntries, s. oben) hinzu.

Problem dabei ist, dass ich ja ein History-Entry - Objekt auch unabhängig erzeugen will, um beispielsweise auch so mal was in die History zu schreieben ("Dokument freigegeben" etc.)

Daher habe ich mir überlegt, eine "HistorySize" - Klasse zu erstellen (siehe Grafik oben). Ob das so 100% Sinn macht kann ich noch nicht sagen  ::)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 27.06.04 - 17:12:12
was ist denn die Aufgabe der HistorySize-Klasse?
was spricht dagegen, dem HistoryEntry ein Attribut Size zu verpassen?
Auch die History selbst könnte ein Attribut Size haben, das ist dann ganz einfach die Größen aller Einträge addiert.

was hindert dich daran, einen HistoryEntry "einfach so" zu erstellen?
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 27.06.04 - 18:10:51
Thomas, ich hab hier mal (nicht UML-konform) zusammengestellt wie ich Deine Vorgehensweise verstehe:
(http://217.160.137.156/user/bp/tmc/_threaduploads/history/historyclass_12.gif)

Was ich hier nicht kapiere:
Wie würde den der Code aussehen, wenn ich unabhängig eine neue Zeile der History hinzufügen will?

Aktuell kann ich ja folgendes machen:
Code
Sub Click(Source As Button)
   Dim session As New NotesSession
   Dim db As NotesDatabase
   Dim doc As NotesDocument   
   Dim uiws As New NotesUIWorkspace
   Dim uidoc As NotesUIDocument
   Dim HistoryEntry As HistoryEntry
   Dim strEntry(0) As String   
   Set db = session.CurrentDatabase
   Set uidoc = uiws.CurrentDocument
   Set doc = uidoc.Document
   strEntry(0) = uiws.Prompt(PROMPT_OKCANCELEDIT,"Historien-Eintrag", "Hier einen Text eingeben:" , "" ,"")
   Set HistoryEntry = New HistoryEntry(doc, 10)
   HistoryEntry.Action =    strEntry
   Call HistoryEntry.write()
   Call doc.save(True,True)
   Call uidoc.refresh
End Sub
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 27.06.04 - 18:24:21
was ist denn die Aufgabe der HistorySize-Klasse?

Ich hatte mir gedacht, dass ich pro Eintrag im Historyfeld ein HistorySize-Objekt erstelle. Also ähnlich wie Du oben vorgeschlagen hast, das über HistoryEntry-Objekte abzubilden.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 27.06.04 - 18:43:58
Was ich hier nicht kapiere:
Wie würde den der Code aussehen, wenn ich unabhängig eine neue Zeile der History hinzufügen will?
mal überlegen...
bevor du einen Eintrag ins Dokumnet schreiben kannst, musst du ja erst prüfen, ob genügend Platz da ist.
Das weiß die History, weil sie ja alle Einträge (und damit deren Gesamtgröße) und auch die maximale Größe kennt.

Im Moment fällt mir dazu folgendes ein: du erstellst einen HistoryEntry und übergibst ihn an eine (noch zu erstellende) Methode der History (z.B. addEntry, falls es die nicht schon gibt).
Die History macht dann das gleiche, was sie auch mit einem "normalen Eintrag" macht (also zum Array hinzufügen, Größe prüfen, schreiben)

so kann ich mir das zumindest vorstellen
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 27.06.04 - 18:51:25
was ist denn die Aufgabe der HistorySize-Klasse?

Ich hatte mir gedacht, dass ich pro Eintrag im Historyfeld ein HistorySize-Objekt erstelle. Also ähnlich wie Du oben vorgeschlagen hast, das über HistoryEntry-Objekte abzubilden.

ok. dann würde diese Klasse nur ein Attribut enthalten (also die Größe selbst)? Dann macht es keinen Sinn, dafür eine Klasse zu bauen.

und eine Klasse, die in Beziehung zu einer anderen steht ist im Prinzip nichts anderes als ein Attribut dieser Klasse. Eben ein etwas komplexeres. Das Attribut Size dürfte bei uns wohl ein Integer oder sowas sein, das kannst du ruhig als Attribut der HistoryEntry-Klasse nehmen.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 27.06.04 - 19:15:09
Aber ist es nicht einfacher, man hält die Aufgaben auseinander?

Also:
HistoryMain:
+ Ausschließlich für PostOpen / Postsave; Zweck ist Feldvergleich und damit
    Aufbereitung des "Actions"-Textes.

HistoryEntry:
+ Einträge ins History-Feld eines Dokumentes schreiben;
   dabei überwachen, dass
     a) Textfeldgröße nicht überschritten wird
     b) Maximal erlaubte Anzahl an Einträgen nicht überschritten wird

(ich denke wahrscheinlich schon wieder viel zu funktionsorientiert.... ::) )
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 27.06.04 - 19:30:06
Aber ist es nicht einfacher, man hält die Aufgaben auseinander?

Also:
HistoryMain:
+ Ausschließlich für PostOpen / Postsave; Zweck ist Feldvergleich und damit
    Aufbereitung des "Actions"-Textes.

HistoryEntry:
+ Einträge ins History-Feld eines Dokumentes schreiben;
   dabei überwachen, dass
     a) Textfeldgröße nicht überschritten wird
     b) Maximal erlaubte Anzahl an Einträgen nicht überschritten wird

nicht in meinen Augen.
nur die History selbst weiß, wieviele Einträge es gibt und wie groß die sind.
sie hat den Überblick und sollte deshalb entscheiden, wer noch ins Dokument darf und wer nicht.

ich kann mir ehrlich gesagt gar nicht vorstellen, wie diese Aufgaben vom HistoryEntry übernommen werden könnten.

Zitat
(ich denke wahrscheinlich schon wieder viel zu funktionsorientiert.... ::) )

das ist wohl möglich. aber nicht ungewöhnlich. du kannst nicht den Schalter umlegen und von heute auf morgen die Denkweise umstellen. das kommt schon noch, wenn du weiter interssiert bleibst und irgendwann mal erkennst, wie simpel man sich das Leben mit dieser Sache machen kann.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: Marinero Atlántico am 28.06.04 - 10:13:45
nicht einfach euch zu folgen. Im Grunde ist die History Size durch das Sternchen in
Code
HistoryMain 1 -------- * HistoryField
schon ausreichend behandelt.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 28.06.04 - 14:55:13
Axel, ich glaube, wir meinen mit der Größe etwas anderes.

Entscheidend ist, dass nur eine begrenzte Menge Text in ein Textfeld geschrieben werden kann.

Jeder History-Eintrag (repräsentiert durch ein HistoryEntry-Objekt) besitzt eine gewisse Textgröße, die man leicht durch die Anzahl der Zeichen ausrechnen kann.
Die Summe der Größen aller Einträge darf einen gegebenen Maximalwert nicht überschreiten, deshalb muss ich das vor dem Schreiben ins Dokument überprüfen.

Und dazu würde ich der Klasse HistoryEntry ein Attribut "Größe" oder "Size", etc. verpassen, das ich abfragen kann.
Wo hast du denn Schwierigkeiten, uns zu folgen?
Ich versuche, heut abend mal ein Diagramm zu malen, vielleicht wirds dann einfacher.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: Marinero Atlántico am 28.06.04 - 15:52:48
Zeitfrage
Bezogen auf dein 1. Diagramm
History ist Creator (Larmann-GRASP) der HistoryEntries.
Es hält eine sortierte Collection der HistoryEntries.  
Es sollte deshalb der Experte für die aggregierte Größe der HistoryEntries sein.
Möglicherweise sollte es diese Information nicht als Membervariable halten, sondern über eine Methode jedesmal neu errechnen.
Vielleicht aber doch als Membervariable.
Wenn ich mich recht erinnere hat man mit diesem Wissen schon 5-8% von IBM 486  ;D

(Dinge wie Larman-GRASP sind auswendig gelerntes Zeugs und soll niemanden abschrecken).
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 28.06.04 - 16:10:25
Zeitfrage
Bezogen auf dein 1. Diagramm
History ist Creator (Larmann-GRASP) der HistoryEntries.
Es hält eine sortierte Collection der HistoryEntries.  
Es sollte deshalb der Experte für die aggregierte Größe der HistoryEntries sein.
Möglicherweise sollte es diese Information nicht als Membervariable halten, sondern über eine Methode jedesmal neu errechnen.
Vielleicht aber doch als Membervariable.

gute Frage. Muss die History die Größe aller aktuellen Entries überhaupt kennen?

das Problem ist, dass wenn ein neuer Eintrag dazukommt, muss ich evtl. einen alten rausschmeißen (oder auch mehrere).
Dazu (habe ich vorgeschlagen) gibt es in der History eine Methode, die ermittelt, welche Einträge geschrieben werden sollen, indem die Methode die Einträge nach der Reihe fragt, wie groß sie sind und dann bei Erreichen der Maximalgröße den Hahn dichtmacht, in dem sie z.B. die überzähligen Einträge aus der Collection entfernt.
Falls nötig, können wir auch eine öffentliche Methode machen, die die Gesamtgröße ermittelt, indem sie wiederum bei, diesmal allen, Einträgen die Größe erfragt, summiert und dem Aufrufer zurückgibt. Also dynamisch, so wie du vorgeschlagen hast. Geht aber auch als Membervariable, die genauso berechnet wird, dann halt immer, wenn sich was an der Collection ändert.

Zitat
Wenn ich mich recht erinnere hat man mit diesem Wissen schon 5-8% von IBM 486  ;D
nicht schlecht. wieviel fehlt uns dann noch zum Bestehen?

gut, dass du mitdiskutierst.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 28.06.04 - 22:03:27
Ich habe jetzt mal doch eine Function geschrieben  ;D :P

Code
Public Function AuxSize(vaSource As Variant, strNewEntry As String, iMaxSizeBytes As Integer, iMaxSizeEntries As Integer) As Variant
   
   On Error Goto ERRORHANDLER
   Dim i As Integer
   Dim j As Integer
   Dim iStart As Integer
   Dim iEnd As Integer
   Dim iAmount As Integer
   Dim iSize As Integer
   Dim iStartNew As Integer
   Dim vaNewValues() As Variant
   
   If  ( Isscalar(vaSource) ) Or ( vaSource(Lbound(vaSource)) = "" ) Then
      Redim vaNewValues(0)
      vaNewValues(0) = strNewEntry
      AuxSize = vaNewValues
      Goto EXITSCRIPT
   End If
   
   iStart = Lbound(vaSource)
   iEnd = Ubound(vaSource) + 1
   '----> Neuen Eintrag dem Array anhängen
   Redim Preserve vaSource(iStart To iEnd) 
   vaSource(iEnd) = strNewEntry
   '<---
   '---> Prüfe wieviele Einträge möglich sind
   iAmount = 0
   'Als erstes ermitteln wir die Anzahl möglicher Einträge anhand der Bytes
   'Als Ergebnis haben wir die Anzahl Einträge in "iAmount"
   For i = iEnd To iStart Step -1
      iSize = iSize + Len(vaSource(i))
      If iSize >  iMaxSizeBytes Then
      'Die Byte-Größe wurde überschritten         
         Exit For 'Schleife verlassen
      Else
         iAmount = iAmount + 1
      End If      
   Next
   'Nun prüfen wir ob die Anzahl erlaubter Einträge dadurch nicht überschritten wird
   If iAmount  > iMaxSizeEntries Then
      iAmount = iMaxSizeEntries
   End If
   
   '---> Jetzt stellen wir das neue Ziel-Array zusammen
   Redim vaNewValues(0 To iAmount-1)
   For j = 0 To iAmount-1
      '--> Wenn das History-Array kleiner wie die max. erlaubte Anzahl-1; starte bei 0;
           'sonst starten wir bei der Differenz (History-Array-Ende - Max.erlaubteAnz. + 1)
      If (iEnd <= iAmount -1 )  Then
         iStartNew = 0
      Else
         iStartNew = iEnd - iAmount + 1
      End If
      '<--
      vaNewValues(j) = vaSource(iStartNew + j)
   Next
   '<---
   AuxSize = vaNewValues
   
   
EXITSCRIPT:
   Exit Function
ERRORHANDLER:
   Call AuxErrorHandler("History ScriptLibrary: Function AuxSize")
   Resume EXITSCRIPT   
End Function

Was macht die Function:

Man kippt folgendes rein:
 - Item-Inhalt des History-Feldes (Variant Array)
 -  neuen Eintrag (str), den wir hinzufügen möchten
 - die maximale Anzahl Bytes die wir zulassen für ein Textfeld
 - die maximale Anzahl Einträge, die das History-Feld haben darf

Zurück bekommt man dann ein Array, welches entsprechend bereinigt ist und man dann direkt ins History-Textfeld setzen kann.

Die Function habe ich geschrieben, um zu zeigen was wir machen müssen.
Nun sollte imho der nächste Step sein, diese Logik via Klassen abzubilden.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 28.06.04 - 22:23:42
Hier noch ein Update der Test-DB zum testen der Function

http://217.160.137.156/user/bp/tmc/_threaduploads/history/history_03.zip (40 KB)



Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 28.06.04 - 22:51:24
Was übrigens auch noch sehr unsauber ist, ist die Abfrage ob es sich um ein neues Dok handelt.

Wenn es ein neues uidoc ist, dann soll ja nix überwacht werden, beim speichern soll nur irgend ein Vorgabetext (z.B. "Neues Dok erstellt.") in die History geschrieben werden.
Wie würde man das am saubersten handeln? Aktuell haben wir ja in der HistoryMain - Klasse nur ein Backend-Doc, aber kein Frontend-Doc (und somit da keine uidoc.isnewdoc - Abfragemöglichkeit).
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 28.06.04 - 23:44:16
Ich habe jetzt mal doch eine Function geschrieben  ;D :P

...

Die Function habe ich geschrieben, um zu zeigen was wir machen müssen.
Nun sollte imho der nächste Step sein, diese Logik via Klassen abzubilden.

*edit* Datenbank hängt ein paar posts weiter unten


ich hab mal wieder ganz schnell was gemacht
ungefähr so, wie ich mir das vorgestellt habe (ungefähr).

Ähem, leider null kommentiert, erklärt, etc. Hüstel.
Und auch nicht kenntlich gemacht, wo ich was geändert habe.
Deswegen schreib ichs hier schnell mal auf

Klasse HistoryEntry
neu:
Property Get Size
Sub readFromDoc
verändert:
Property Set Action

Klasse HistoryMain
neu:
Const MAX_SIZE
Attribut m_HistoryEntries()
Sub initEntries()
Sub clear()
Function getMaxEntries()

verändert:
Sub new()
Sub save() (nur ne Messagebox)
Sub write

Viel Spaß ;D

*edit* da fehlt übrigens noch ein bisschen was, das mach ich noch. Funktionieren tuts schon mal, zumindest oberflächlich
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 28.06.04 - 23:51:10
Was übrigens auch noch sehr unsauber ist, ist die Abfrage ob es sich um ein neues Dok handelt.

Wenn es ein neues uidoc ist, dann soll ja nix überwacht werden, beim speichern soll nur irgend ein Vorgabetext (z.B. "Neues Dok erstellt.") in die History geschrieben werden.
Wie würde man das am saubersten handeln? Aktuell haben wir ja in der HistoryMain - Klasse nur ein Backend-Doc, aber kein Frontend-Doc (und somit da keine uidoc.isnewdoc - Abfragemöglichkeit).

aber NotesDocument.isNewNote
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 28.06.04 - 23:55:22
aber NotesDocument.isNewNote

ups, stimmt  :D

Na dann sollte es nicht weiter schwierig sein  :)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 28.06.04 - 23:56:21

*edit* da fehlt übrigens noch ein bisschen was, das mach ich noch. Funktionieren tuts schon mal, zumindest oberflächlich

was fehlt noch?

wenn nicht alle Entries geschrieben werden, dann wird die Anzahl der Entries (Membervariable m_EntryCount) nicht aktualisiert.
Und der Array, der die Entries hält wird auch nicht angepasst.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 28.06.04 - 23:59:05
ich hab mal wieder ganz schnell was gemacht
ungefähr so, wie ich mir das vorgestellt habe (ungefähr).

Cool, danke.
Funktioniert auf den ersten Test hin.

Eine Bitte:
Hab gerade gesehen, dass Du Boolean als Datentyp verwendest, denn es leider erst ab R6 gibt. Vielleicht kannst Du den noch zu Integer oder so machen....

Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 29.06.04 - 00:09:09
ich versuche, nächstes Mal daran zu denken
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 29.06.04 - 00:11:47
History ist Creator (Larmann-GRASP) der HistoryEntries.
Es hält eine sortierte Collection der HistoryEntries.  
Es sollte deshalb der Experte für die aggregierte Größe der HistoryEntries sein.

das ist genau der Punkt.
Die History ist der Experte für die aggregierte Größe der HistoryEntries sein.
das hätte niemand anders besser ausdrücken können.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 29.06.04 - 00:17:19


ich hab mal wieder ganz schnell was gemacht
ungefähr so, wie ich mir das vorgestellt habe (ungefähr).

Ähem, leider null kommentiert, erklärt, etc. Hüstel.
Und auch nicht kenntlich gemacht, wo ich was geändert habe.

das ist das Problem, wenn ich was schnell mache.
da ist irgendwo noch ein dicker Fehler.
der erste History-Eintrag wird irgendwie mit dem zweiten überschrieben
bin zu müde, um zu debuggen. mach ich morgen (oder im Lauf der Woche)
wichtig ist aber, dass das Prinzip klar wird.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 29.06.04 - 00:21:10


ich hab mal wieder ganz schnell was gemacht
ungefähr so, wie ich mir das vorgestellt habe (ungefähr).

Ähem, leider null kommentiert, erklärt, etc. Hüstel.
Und auch nicht kenntlich gemacht, wo ich was geändert habe.

das ist das Problem, wenn ich was schnell mache.
da ist irgendwo noch ein dicker Fehler.
der erste History-Eintrag wird irgendwie mit dem zweiten überschrieben
bin zu müde, um zu debuggen. mach ich morgen (oder im Lauf der Woche)
wichtig ist aber, dass das Prinzip klar wird.

Geht wohl jedem so :-)
Kann ich mir auch ansehen (aber eben auch nicht mehr heute...)

Das Prinzip zeigst Du damit prima.

Wir haben auch noch ein paar andere Bugs drin (stammen aber von mir; z.B.: Neues Dok, 3mal speichern ohne zu schließen: es wird jeweils eine Zeile "New doc created" angelegt). Werde die auch noch ausbügeln.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 29.06.04 - 19:24:58
Bug weg.
Boolean weg.
Kommentare da
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 29.06.04 - 20:06:42
Danke Thomas.

Habe in der angehängten DB die ns5 kurz angesehen.
Kann es sein dass Du noch einen älteren Stand angehängt hast?

Auf den ersten Blick ist wohl Bug weg, aber Boolean ist noch da (History Main Klasse, Zeile 26). Oder einfach übersehen? Kann ich aber auch rausnehmen, no problem...

Ich warte jetzt lieber noch mit dem weiteren anschauen, nicht dass Du noch einen anderen Stand hast  ;)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 29.06.04 - 20:54:45
oh, ich hatte nach "boolean" gesucht, aber nix gefunden.
habs ausgebessert.

der Stand ist der, den du mal gepostet hast (history02.nsf).
nicht der letzte von dir.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 29.06.04 - 21:49:30
Ah. ok.

Ich habe jetzt Deine Version 02 genommen, und meine Bugs ausgebessert.

Außerdem noch die maximale Anzahl Einträge eingebaut (steht in global Declarations der Maske, im Beispiel "4") in der Function getMaxEntries der HistoryMain - Klasse.

Hier also der aktuelle Stand:
http://217.160.137.156/user/bp/tmc/_threaduploads/history/history_04.zip
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 29.06.04 - 22:03:31
so ein Mist. Ich hatte alle miene Änderungen im Nachhinein kommentiert, aber irgendwie scheinbar nicht abgespeichert. Schade.
Vielleicht kann ich mich morgen nochmal dazu aufraffen.
Na ja, du hast es scheinbar auch ohne Kommentare gecheckt.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 29.06.04 - 22:07:38
Na ja, du hast es scheinbar auch ohne Kommentare gecheckt.

Ich hangle mich so durch  :)
Ist zwar etwas hin- und herspringerei zwischen den Klassen, Functions etc. aber komm dann schon drauf :-)

Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 29.06.04 - 22:11:05
Noch eine Frage:

Warum gibt es diese Sub in der History Main?
Code
   Private Sub clear()
      Call m_doc.ReplaceItemValue("History", "")
   End Sub

Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 29.06.04 - 22:14:50
die löscht alle Einträge aus dem Dokument.
dann schreib ich alle Einträge, die ins Feld passen wieder rein.

Also statt die überschüssigen Einträge aus dem Dokument zu entfernen schmeiße ich erstmal alle raus und schreibe nur die gewünschten wieder rein.
Das erschien mir der einfachere Weg
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 29.06.04 - 22:18:44
ich gebe zu, es ist nicht sehr fein, weil die Klasse somit auch Feldnamen kennen muss.
Vielleicht wäre es besser, der HistoryEntry-Klasse eine Delete-Methode zu verpassen. Sehr wahrscheinlich sogar.
Das erste Refactoring kommt bestimmt...
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 29.06.04 - 22:30:36
Ah, ok.
Die Frage kam u.a. daher, weil ich in meiner Version "03" in der Sub write() der History Entry Klasse den Code "Set m_itmHistory = m_doc.ReplaceItemValue( m_strHistoryFieldName, m_vaTarget )" hatte, also direkt reinschrieb / überschrieb.

Ansonsten war mir das auch klar, dass vorgegebene Feldnamen wie "History" nicht besonders elegant ist (kam glaub ich ja ursprünglich von mir aufgrund Faulheit).

Sollte imho auch mehr- oder weniger zentral definiert werden; evtl. in den Global Decs der Maske (und dann via Objekt "HistoryMonitorDoc" in das History-Objekt kippen.)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 29.06.04 - 23:01:12
Hab gerade ein Debug-Problem (in R5) festgestellt:

Wird bei laufendem Debugger ein "Save" durchgeführt kommt überhaupt nix. Nur wenn ich einen Error = XY einbaue, kommt erst die Fehlermeldung, und dann erst sehe ich den Debugger.

Ist das ein Notes-Bug? Scheint wohl so  ::)


*edit* Ich platziere das Problem mal separat im R5-Problemforum, da wird das eher wie hier mittendrin....
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 01.07.04 - 20:52:18
Ich habe eine Frage zur geplanten Klasse "Field":

zu den Hilfsfunktionen:
Explode und ErrorHandler sind Kandidaten für eine 'Hilfsfunktions-Bibliothek'

die anderen haben alle was mit Feldern zu tun (gib mir Werte, zeig mir Unterschiede, ...) damit haben wir einen neuen Kandidaten für eine Klasse 'Feld'. die all diese Funktionalität zur Verfügung stellt.

ich habe Anmerkung zu der neuen Klasse.

Was du gemacht hast ist, vereinfacht ausgedrückt, die Funktionen gepackt, in eine Bibliothek gepackt und 'Class' drum herum geschrieben.

Das ist nix Schlimmes, nur ist das nicht so ganz das, was ich mir vorgestellt habe, als ich schrieb, wir brauchen eine Feld-Klasse, und das ist ja auch nicht schlimm.

Da wir hier aber in einem Thread sind, in dem es darum geht, wie man geschickt objektorientiert analysiert, entwirft und programmiert, versuche ich zu erklären, was ich beim Schreiben im Kopf hatte.
Ein Objekt der Klasse 'Feld' repräsentiert genau ein zu überwachendes Feld aus dem Notesdokument. D.h., wenn ich drei Felder überwachen will, dann brauche ich drei Objekte. Jedes Objekt kann mir Auskunft darüber geben, welchen Wert 'sein' Feld hat, welchen es ürsprünglich hatte bzw. worin der Unterschied zwischen den beiden Werten besteht.
Unser History-Objekt müsste alle Feld-Objekte instanziieren und würde so alle kennen. Wenns dann zum schreiben der Änderungen geht, frägt das History-Objekt der Reihe nach seine Feld-Objekte nach ihren Änderungen und gibt die Ergebnisse an das HistoryEntry-Objekt oder evtl. noch besser, sie übergibt die Feld-Objekte an das History-Entry-Objekt und das fragt selbst nach.

Wir könnten hier das gleiche Prinzip anwenden, wie ich bei der HistoryEntry-Klasse vorgeschlagen habe, also eine abstrakte Basisklasse 'Feld' und davon abgeleitete Klassen 'Textfeld' und 'RTFFeld'
(ich hab da in deinem Code irgendwas mit "I AM RTF" gesehen, ich weiß zwar nicht genau, wofür das ist, aber evtl. könnte man sowas durch solche Subklassen umgehen...)

Ich habe ja bisher 2 Functions hierfür:
a) Differences: Man kippt 2 Arrays rein: 1 Array mit den bisherigen Feldinhalten (Inhalt von Company, Street, City etc.) und 1 Array mit den neuen Feldinhalten.
Als Ergebnis erhält man dann Array, das alle Änderungen enthält.

b) ItemValuesToArray
Hier kippt man ein NotesDocument und ein Array (Namen der Felder) rein und erhält die Feldinhalte als Array

So richtig verstehe ich jetzt nicht, was mir nun ein Objekt pro Feld hier bringt.
Denn die Abarbeitung der Objekte müsste ich dann doch wieder z.B. über eine Function machen (ItemValuesToArray z.B......), die ja wohl nicht in der Feld-Klasse Sinn macht.

Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 01.07.04 - 21:25:55
ich bin nicht mehr so ganz auf dem Laufenden, ich versuche mal zu erklären

also die Klasse Feld könnte ungefähr so aussehen.

Attribute:
anfangswert
endwert
(evtl. das notesitem)

Methoden:
getUnterschied

So, die History würde also für jedes zu überwachende Feld ein Objekt erzeugen und die Attributwerte setzen (vorher, nachher).
Wenn die History einen HistoryEintrag veranlassen möchte, frägt sie erstmal jedes Feld: "Gibts du mir bitte deine Unterschiede?"
Das Feld tut das, die History baut sich daraus was zusammen und übergibt das an den HistoryEintrag.

Vorteil(e)

du kannst diese Feld-Klasse in anderen Applikationen unverändert einsetzen. Es kann ja vorkommen, dass du mal nicht die Unterschiede mehrerer Felder in einem Array brauchst, sondern einzeln oder auch ganz anders kombiniert.
Du kannst dich darauf verlassen, ein Feld-Objekt gibt dir immer den UNterschied. Was du damit machst kann variieren.
Deine beiden Funktionen kannst du nur in diesem Anwendungsfall nutzen.
Für andere Fälle müsstest du neue Funktionen machen, die sich vielleicht sogar nur marginal unterscheiden, oder die bestehenden Funktionen erweitern (mit if..then, o.ä.).

was auch noch cool sein könnte: wenn du die Klasse Feld abstrakt machst und davon spezielle Klassen ableitest (z.B. Textfeld, RTFeld, Zahlfeld),
dann wärst du sehr variabel bei der Form der Unterschiede.
D.h. ein Textfeld gibt die den Unterschied als Text zurück, ein RTFeld gibt dir Datum der Änderung zurück, ein Zahlfeld gibt dir eine Differenz/Summe zurück, etc.
Da können beliebig viele Spezialfälle hinzukommen, dein Code, der die Unterschiede vom Feld-Objekt verlangt, muss sich nicht ändern (oder nur sehr gering) Die Spezialbehandlung erfolgt in den jeweiligen Klassen, darum brauchst du dich als Nutzer der Klassen nicht kümmern (natürlich musst du es vorher programmieren).

ich glaube, dass ich das noch nicht klar rübergebracht habe.
Hak bitte nach, wenn nötig
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 01.07.04 - 21:50:22
Danke Thomas, ist nun verständlich und klingt auch sehr sinnvoll.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 02.07.04 - 20:54:05
Was ich noch nicht ganz kapiere ist der Zusammenhang Field-Objekt mit FieldText-Objekt.
Hatten wir ja glaub ich auch schon bei HistoryEntry und HistoryEntryText etc.

Wie ich das sehe:
Das Field-Objekt ist ein Auto.
Das FieldText-Objekt ist der Reifen vorne Links.

Was ich gesehen habe wird das Auto kursiv in den UML-Diagrammen dargestellt. Ich glaub ich kann dann auch das Auto-Objekt nicht direkt erzeugen. Ich fange beim Reifen an.

Wie sind denn hier die Zusammenhänge? Und: Warum ist das Auto "kursiv"? Warum mache ich nicht ein normales Auto-Objekt, welches dann auch Objekte wie Reifen vorne links und Fahrersitz enthält?

(wohl eine absolute Beginner Frage)

Matthias
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 02.07.04 - 22:05:08
Was ich noch nicht ganz kapiere ist der Zusammenhang Field-Objekt mit FieldText-Objekt.
Wie ich das sehe:
Das Field-Objekt ist ein Auto.
Das FieldText-Objekt ist der Reifen vorne Links.

falsch.
das ist Vererbung.
Field ist ein Auto.
FieldText ist ein Sportwagen.
FieldRTF ist ein Kombi.
FieldNumbers ist ein Jeep.

Alle sind Autos und alle haben was gemeinsam. Aber bei speziellen Dingen unterscheiden sie sich.
Bei unseren Feldern wäre z.B. eine Gemeinsamkeit, dass alle eine Wert vor und einem nach dem Speichern haben können.
Das Spezielle ist, dass jede Feld-Art den Unterschied zwischen Vor- und Nachher anders "berechnet".

Zitat
Was ich gesehen habe wird das Auto kursiv in den UML-Diagrammen dargestellt. Ich glaub ich kann dann auch das Auto-Objekt nicht direkt erzeugen. Ich fange beim Reifen an.

Wie sind denn hier die Zusammenhänge? Und: Warum ist das Auto "kursiv"? Warum mache ich nicht ein normales Auto-Objekt, welches dann auch Objekte wie Reifen vorne links und Fahrersitz enthält?

Auto ist kursiv, weil es das nicht wirklich gibt. Es gibt nur Jeeps, Cabrios, Kombis, Limousinen, etc.
Auto ist der Oberbegriff für alle.

Feld ist kursiv, weil es kein allgemeines Feld bei uns gibt (wir erinnern uns: kursiv bedeutet abstrakte Klasse, d.h. von dieser Klasse kann keine Instanz erzeugt werden, weil es die ja gar nicht geben kann.)

Ein schönes Beispiel aus "Head First Java" (frei übersetzt):

Es gibt eine Klasse "Tier"
Von dieser erben die Klassen "Canidae" und "Felidae".

Von "Canidae" erbt "Hund", "Wolf"
Von "Felidae" erbt "Katze", "Löwe"

Es macht Sinn, Objekte der Klasse "Hund", "Wolf", "Katze" und "Löwe" zu erstellen.
Aber was genau ist ein "Tier"-Objekt??
Welche Form hat es? Welche Frabe, Größe, Anzahl an Beinen...

Wenn du versuchst, ein "Tier"-Objekt zu erstellen, dann ist das wie ein verheerender Transporterunfall in StarTrek. So einer, wo bei Beam-Vorgang irgenwas schlimmes mit dem Puffer (der, in dem die Transportmuster sind) passiert.

Du brauchst aber trotzdem eine Klasse, die Gemeinsamkeiten vererben kann. Um zu vermeiden, dass Objekte einer Klasse erstellt werden, für die das keinen Sinn macht, machst du die Klasse abstrakt.
Zumindest in Java. In LotusScript gibt es keine abstrakten Klassen, ich tue aber so, als ob.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 02.07.04 - 22:12:01
Danke Thomas, nun wird für mich vieles klarer :-)

Sehr gute Erkärung.

Na ja, nächste Frage kommt bestimmt noch, aber das ist ja u.a. auch Sinn und Zweck dieses Threads  ;)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 05.07.04 - 21:16:05
Neue (allgemeine) Frage:

Wann nehme ich "sub new(irgendwas as ...)" und wann "Public Property Set", um meinem Objekt Eigenschaften zu geben?

OK, sub new() geht ja nur, wenn ich das Objekt erzeuge.

Warum ich frage:
Es könnte ja sein, dass ich in der Klasse eine Function habe, die braucht aber unbedingt eine Variable. Soll man da dann die Variable gleich zu Beginn der Objekterzeugung geben lassen (eben über sub new) Aber vielleicht kenne ich die am Anfang noch gar nicht?
Denn wenn die Property nicht gesetzt ist (Public Property Set...), dann erhalte ich einen Fehler, weil ja die Function eine Variable braucht.

Ich hoffe meine Frage ist einigermaßen verständlich....  ::)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 05.07.04 - 21:32:13
Noch ne Frage zu abstrakten Klassen:

So wie ich das jetzt kapiere, versucht man wohl, so viel wie es Sinn macht in eine übergeordnete, abstrakte Klasse zu packen - und nur die Unterschiede dann in die darunterliegenden Klassen. Um auch u.U. später neue darunterliegende Klassen erzeugen zu können.

Wie ich oben in einem Code gesehen habe, ruft man die Abstrakte Klasse via
"Public Class UNTERKLASSE As ABSTRAKTEKLASSE" auf.

Ich habe damit auch Zugriff auf private Membervariablen der "ABSTRAKTEKLASSE".
Was kann ich noch alles auslagern in eine abstrakte Klasse? Functions/Subs wohl bestimmt.
Get/Set-Methoden gehen wohl nicht, wenn ich von da aus eine Function einer Unterklasse aufrufen will. Denn die abstrakte Klasse lässt sich dann nicht kompilieren.....

Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: Semeaphoros am 06.07.04 - 00:31:19
Zuerst mal zur ersten Frage, tatsächlich macht es Sinn, möglichst früh irgendwleche Member-Variablen zu besetzen, vor allem, wenn sie später unbedingt gebraucht werden, also wenn immer möglich werden die schon mit New initialisiert, wenn das nicht geht, dann muss man eben über eine setter-methode arbeiten. Man kann das aber auch kombinieren, indem eine Setter-Methode definiert und bei New überprüft, ob der Parameter gültig ist, wenn ja, wird von New aus die Setter-Methode aufgerufen.

Zu den abstrakten Klassen (wobei das in diesem Falle irrelevant ist, ob die Oberklasse abstrakt ist oder "konkret", abstrakt besagt ja nur, dass man diese Klasse selbst nicht instanziieren kann (oder im Falle von LS sollte) und hat sonst nix zu bedeuten).

Du kannst alles in die Basisklasse hinüberbringen, was Sinn macht, inklusive Setter- und Getter Methoden. Die werden alle schön brav mitvererbt. Vielleicht studierst Du mal die Vererbung in der Hilfe und die für LS besondere Schreibweise, wenn eine an sich überschriebene Methode der Basisklasse aufgerufen werden soll, da gibts dann die besondere DotDot-Notation:

Basisklase..MethodeDerBasisklasse

Für Fortgeschrittene zum Nachschlagen: Early binding und Late Binding spielt hier auch eine Rolle (und dann sind wir schon bald einmal bei abstrakten Methoden). Um, das ist schon eine geballte Ladung, aber gibt vielleicht eine Idee davon, dass wir es hier mit einer ziemlich komplexen Vererbungsstruktur zu tun haben.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 06.07.04 - 20:06:09
Danke, Jens, für die Infos.

Gerade DotDot - Notation ist da für mich sehr hilfreich.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 06.07.04 - 21:08:25
Nun hänge ich wieder fest:

Ich habe 1 sozusagen abstrakte Klasse.

Da steht u.a. drin:
Code
   Public Property Get myDifference As Variant
      myDifference = .getDifference("Wert 1")
   End Property      

Dann habe ich eine Unterklasse ("HistoryField2Text"), da ist u.a. folgende Function:
Code
   Private Function getDifference(strTest As String) As String
      getDifference = strTest & "bla bla"
   End Function

Nun habe ich einen Button in einer Maske mit folgendem Code:
Code
Sub Click(Source As Button)
   
   Dim myHiFiText As HistoryField2Text
   Dim test As Variant   
   test = myHiFiText.myDifference
   Msgbox test   
   
End Sub

Beim Ausführen kommt in der Zeile "test = myHiFiText.myDifference" die Fehlermeldung "Object Variable not set".

Any idea?
Ich habe bewusst nicht den ganzen Code zwecks Übersichtlichkeit gepostet. Wenn nötig hänge ich den aber natürlich rein.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: Semeaphoros am 06.07.04 - 21:20:36
Füge mal ein:

Set myHiFiText = New HistoryField2Text

irgendwo nach dem Dim myHiFiText
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 06.07.04 - 21:24:50
Jo mei, klar, danke. (ist ja schon fast peinlich  :-[, egal da muss ich durch :) )
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 06.07.04 - 21:34:30
Nächste Fehlermeldung im o.g. Beispiel:
"Named product object does not exist"

Fehlermeldung kommt in Zeile "myDifference = .getDifference("Wert 1")" (steht in der abstrakten Klasse).

Erscheint mir so, dass die Function "getDifference" nicht gefunden wird....

Lt. Debugger werden sauber beide sub new() der Klassen durchlaufen.

Was möchte ich überhaupt:
In der abstrakten Klasse eine Property definieren, aber den Code dann in einer Unterklasse haben.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 06.07.04 - 21:36:39
arbeitest du noch mit einem Modell?
wenn ja wärs schön, wenn du das mal posten könntest, dann könnten wir deine Fortschritte analysieren :D
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 06.07.04 - 21:43:54
Sorry, nicht wirklich Thomas  :P

Mein nächstes Ziel ist es jetzt, eine Klasse HistoryField zu erstellen.

Wobei HistoryField abstrakt sein soll, und daraus abgeleitet eben HistoryFieldText, HistoryFieldRTF etc. Also so wie von Dir schon vorgeschlagen.

(http://www.atnotes.de/attachments/snapfield.gif)

Bevor ich das mache, will ich aber erst mal Basics kapieren. Daher teste ich noch ein wenig rum, bevor ich loslege. Aktuell versuche ich eben, eine Property in der abstrakten Klasse zu Setten, aber der eigentliche Code läuft dann in einer Unterklasse (HistoryFieldText / HistoryFieldRTF, etc.).

Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 06.07.04 - 21:45:21
Fehlermeldung kommt in Zeile "myDifference = .getDifference("Wert 1")" (steht in der abstrakten Klasse).
also diese Schreibweise habe ich noch nicht gesehen.

wenn ein Objekt eine Methode von sich selbst aufruft, kann das auf 2 Arten erfolgen:

entweder Me.getDifference()
oder einfach getDifference()


Was du willst, kannst du erreichen, wenn du in dre Basisklasse die Methode hast und ebenfalls in den Subklassen.
In der Basisklasse hast du allerdings nur die Signatur der Methode, die Implementierung machst du in den Subklassen.

D.h. in der Basisklasse steht wirklich nur

Public Property Get Wert As String
End Property

Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 06.07.04 - 21:49:37
in dem Link, den du im Tipps Bereich gepostet hast
(http://www.lotusgeek.com/SapphireOak/LotusGeekBlog.nsf/plinks/ROLR-5UV6YM (http://www.lotusgeek.com/SapphireOak/LotusGeekBlog.nsf/plinks/ROLR-5UV6YM))
da ist ein Posting von mir, dass zeigt, wie du das machen kannst.
Da sind zwei Klassen (AbstractImportFactory und ExcelFactory).
In der AbstractImportFactory ist die Methode init(), allerdings nur die Signatur.
In der Excel Factory gibts die Methode auch, hier ist die wirkliche Funktionalität implementiert.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 06.07.04 - 22:09:01
Fehlermeldung kommt in Zeile "myDifference = .getDifference("Wert 1")" (steht in der abstrakten Klasse).
also diese Schreibweise habe ich noch nicht gesehen.

 ;D

Ich hatte da 1 + 1 zusammengezählt bei der DotDot-Notation  ;D

Habe es aber jetzt so verstanden:
Ich muss also in der Basisklasse (hier = abstrakte Klasse) die Function/Sub genau so reinschreiben (Function / End Function), aber nur ohne Code dazwischen. Nur dann kann ich dann auch auf die Unterklassen - Function/Sub zugreifen.

Danke, so klappt es auch jetzt  :D
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 06.07.04 - 22:17:52
Habe es aber jetzt so verstanden:
Ich muss also in der Basisklasse (hier = abstrakte Klasse) die Function/Sub genau so reinschreiben (Function / End Function), aber nur ohne Code dazwischen. Nur dann kann ich dann auch auf die Unterklassen - Function/Sub zugreifen.

jein.
1. In der Methode der abstrakten Klasse kann sehr wohl auch Funktionalität implemetiert sein. Funktionalität, die in allen Subklassen benötigt wird (damit du nicht redundanten Code hast).

Diese Methode in der Basisklasse

Sub doIt()
   Print "Basisklasse"
End Sub

und diese in der Subklasse

Sub doIt()
   Call Basisklasse..doIt()
   Print "Subklasse"
End Sub


2. (aber nicht groß drüber nachdenken, ist nicht so wichtig und verwirrt an dieser Stelle wohl nur) Du musst die Methode nicht zwingend in der Basisklasse haben.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 06.07.04 - 22:27:26
2. (aber nicht groß drüber nachdenken, ist nicht so wichtig und verwirrt an dieser Stelle wohl nur) Du musst die Methode nicht zwingend in der Basisklasse haben.

Dann hab ich das glaub ich richtig verstanden (nur nicht verständlich rübergebracht).

Genau das war mein Ziel:
- Wiederkehrendes an 1 Stelle (hier: abstrakte Klasse)
- Spezielles in die abgeleiteten Klassen
- Der Call aber immer gleich (wenn ich Call sportauto.Feature mache, soll sich die Lachgaseinspritzung einschalten, wenn ich Call cabrio.Feature mache, soll sich das Dach öffnen).
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 07.07.04 - 22:59:09
OK, ich stecke nun mittendrin.

Damit das nun überhaupt noch wer kapiert von was ich rede, hole ich etwas weiter aus:

Wir haben als Aufgabe, Feldänderungen einer Maske in eine History zu schreiben.
Um das zu machen, habe ich
+ alle Feldnamen
+ alle Feldtitel (die ja abweichen können vom Feldnamen, z.B. Titel "Inhalt", Name aber "Sbj1")
+ alle Feldinhalte
jeweils in einem Array.

Um z.B. das Array "Feldinhalte" zu erzeugen, nutze ich eine Function:
Private Function ExtItemValuesToArray(doc As NotesDocument, vFieldList As Variant) As Variant

Nun sagt Thomas zurecht: Du hast ja da eine ScriptLib, wo Du Felder behandelst, mach doch daraus eine Klasse "Field".
Zitat
Ein Objekt der Klasse 'Feld' repräsentiert genau ein zu überwachendes Feld aus dem Notesdokument.
D.h., wenn ich drei Felder überwachen will, dann brauche ich drei Objekte. Jedes Objekt kann mir Auskunft darüber
geben, welchen Wert 'sein' Feld hat, welchen es ürsprünglich hatte bzw. worin der Unterschied zwischen den beiden Werten besteht.


Das mache ich auch jetzt dann.

Mein Problem ist jetzt:
Ich muss ja den einzelnen Objekten u.a. Feldinhalte geben.
Bisher mach ich es mir einfach.

Code
Private Function ExtItemValuesToArray(doc As NotesDocument, vFieldList As Variant) As Variant
   '**************************************************************************************************
   'Purpose: Loops through the provided field list and puts the item values to an Array
   '   
   'In case of RichTextField, it sets a prefix "I_AM_A_RTF" and the last modified date. So we 
   'are easily able to find out if the array-entry-source was richtext.
   '**************************************************************************************************   
   
   On Error Goto ERRORHANDLER
   
   Dim item As NotesItem
   Dim vItemValues() As Variant
   Dim strItemValue As String
   Dim i As Integer
   
   'We loop through the field list and set the item values to the HistorySourceArray
   Redim vItemValues(Ubound(vFieldList))
   For i = 0 To Ubound(vFieldList)
      Set item = doc.GetFirstItem( vFieldList(i) )
      If item.Type = RICHTEXT Then
         vItemValues(i) = "I_AM_A_RTF" & Cstr(item.LastModified)
      Else
         '--> We find out if the item contains more than one value; if so: we put 'em together in a string      
         strItemValue = ""
         Forall v In item.values
            If strItemValue = "" Then
               strItemValue = Cstr(v)
            Else
               strItemValue = strItemValue & " / " & Cstr(v)
            End If
         End Forall
         '<--------------
         vItemValues(i) = strItemValue
      End If 'item.Type = RICHTEXT Then
   Next
   
   ExtItemValuesToArray = vItemValues
   
EXITSCRIPT:
   Exit Function
ERRORHANDLER:
   Call AuxErrorHandler("ExtItemValuesToArray")
   Resume EXITSCRIPT
End Function

Damit mache ich mir ein Array aus den Feldinhalten eines Dokumentes. Ich sehe dabei auch sofort, ob ein Array-Eintrag aus einem RT-Feld stammt und kann das dann weiterbearbeiten.

Unser Zielanspruch ist aber, mehrere Unterklassen zu haben (FieldText, FieldRTF, etc.).

Wie gebe ich jetzt die Feldinhalte in die Klassen FieldText und FieldRTF?
Ich müsste dann ja im Code abfragen, um was es sich für ein Feld handelt, und dann die entsprechende Klasse erstellen.

Dann habe ich eine Ansammlung an Objekte als Ergebnis: Einige FieldText-Objekte und einige FieldRTF-Objekte (kunterbunt gemischt).

Bisher war die Ausgabe der Reihenfolge in die Historie vorgegeben durch die Reihenfolge im Array. Jetzt muss ich wohl zusätzlich noch einen Zähler mitlaufen lassen um die Reihenfolge zu beizubehalten.

Außerdem blähe ich so den Code auf in dem ich die Objekte erstelle. All das hatte ich mit der Function vermieden.

Fazit:
Mittlerweile sehe ich nicht mehr so ganz den Sinn, eine Field-Klasse zu erstellen um z.B. obengenannte Function abzulösen.

Aber vielleicht kann mir das wer erklären (wenn da jetzt überhaupt noch wer durchsteigt  ::) )

Danke
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 07.07.04 - 23:04:35
Hier noch ein wenig Code als Ansatz für die Field-Klasse.

a) Die abstrakte Klasse
Code
Public Class HistoryField2

   Private m_vInitialValue As Variant
   Private m_vNewValue As Variant
   Private m_strTitle As String
   Private m_vDifference As Variant

   '-------------------------------------------------------------------------------------------------
   'Get/Set-Methoden
   Public Property Set NewValue As Variant
      m_vNewValue = NewValue
   End Property
   Public Property Get Difference As Variant
      Difference = getDifference(m_strTitle, m_vInitialValue, m_vNewValue)
   End Property
   '-------------------------------------------------------------------------------------------------
   Public Sub new(strTitle As String, vInitialValue As Variant)
      m_strTitle = strTitle
      m_vInitialValue = vInitialValue
   End Sub
   '-------------------------------------------------------------------------------------------------
   Private Function getDifference(strName As String, vSource As Variant, vTarget As Variant) As String
      'Nichts. Code wird in der abgeleiteten Klasse ausgeführt !
   End Function
   '-------------------------------------------------------------------------------------------------
End Class

b) Eine Unterklasse
Code
Public Class HistoryField2Text As HistoryField2
%REM
Diese Klasse nutzt die abstrakte Klasse "HistoryField2 !
%END REM
   '-------------------------------------------------------------------------------------------------   
   Public Sub new(strName As String, vInitialValue As Variant)
      
   End Sub
   '-------------------------------------------------------------------------------------------------      
   Private Function getDifference(strName As String, vSource As Variant, vTarget As Variant) As String
      Dim strResult As String
      If vSource = vTarget Then
      Else 'Nein, Quelle und Ziel sind nicht identisch
         strResult = AuxImplode(vSource, " / ") 'erstmal alles in ein String   
         strResult = AuxRemoveLinebrakes(strResult, " ")
         strResult = "Changed Field '" & strName & "' (former value: '" & strResult & "')"
      End If
   End Function
   '-------------------------------------------------------------------------------------------------      
End Class

Hier brauch ich aber noch eben die ursprünglichen Feldinhalte, und dann auch die neuen Feldinhalte.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 07.07.04 - 23:22:28
Kommando zurück:

Ich habe glaub ich den Fehler gemacht, auf den bisherigen Code was aufzusetzen.

Was imho besser wäre, nochmal neu anzufangen.

- Man hat ein Dokument und öffnet dieses
- dabei schreibt man pro zu überwachendes Feld was in ein FieldObjekt (Name, Inhalt, etc.)
- Beim Speichern schreibt man zusätzlich die neuen Werte in die FieldObjekte und lässt sich die Unterschiede geben.

Der bisherige Codeteil ist dafür nicht wirklich brauchbar.
Ich glaube das beste ist es das ganze nochmal neu aufzusetzen.

Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 07.07.04 - 23:44:02
ich versuche mal zu beschreiben, was ich jetzt verstanden habe kombiniert mit dem, was ich mir dachte.

du sagst, du erstellst verschiedene Feld-Objekte. Das ist gut so.
Wo erstellst du die denn?
Ich dachte, dass das History-Objekt, diese Feld-Objekte erstellt.
Das History-Objekt holt sich (woher ist egal) eine Liste aller zu überwachender Felder.
Es erzeugt dann auf Basis dieser Liste alle nötigen Feld-Objekte und hält diese Objkete in einem Array (sozusagen als Membervariable)
Beim Erzeugen muss das History-Objekt ermitteln, welches spezielle Feld-Objekt  erzuegt werden muss.
Dem Konstruktor des Feld-Objekts wird das entsprechende NotesItem-Objekt als Parameter mitgegeben, das Feld-Objekt hält dieses NotesItem-Objekt als Membervariable.
Das Feld-Objekt holt sich dann seinen Initialwert aus diesem Feld. (Private Methode, die vom Konstruktor aufgerufen wird.

Wenn jetzt ein neuer History-Eintrag gemacht werden muss, dann tritt ja wieder unser History-Objekt in Aktion, es muss ja das HistoryEntry-Objekt erstellen.
Dem HistoryEntry-Objekt muss es allerdings den Text mitgeben, der im Eintrag stehen soll.
Deshalb fragt das History-Objekt nun alle seine Feld-Objekte:
"Gib mir doch bitte mal das Delta zwischen deinem Initialwert und dem, der jetzt in deinem NotesItem drin steht."
(Jetzt kommt das mit der Reihenfolge. Das verstehe ich nicht. Die ist ja immer die gleiche. Dieses Fragen ist eine Schleife über den Array mit den Feld-Objekten, und die verändern nicht die ihre Position innerhalb des Arrays)

So, die History bekommt von jedem Feld eine Antwort und erstellt daraus etwas Geeignetes, um es dem HistoryEntry zu übergeben, der das Ganze dann ins Dokument schreiben soll.

So, das wars.

Du hast recht, dass das ein paar mehr Zeilen Code sind.
Dafür gewinnst du ein sehr großes Maß an Flexibilität.

Du kannst, wenn die History mal etwas anders aussieht, als jetzt (1 Textfeld) immer noch deine Feldklassen einsetzen - unverändert.
Was du ändern musst ist, was die History mit dem Delta eines Felds macht bevor es an den HistoryEntry gegeben wird.

Ich versuche mal, am WE (muss schaun, ob ich Zeit hab) sowas in die letzte hier angehängte Version der DB einzubauen.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 07.07.04 - 23:45:16
- Man hat ein Dokument und öffnet dieses
- dabei schreibt man pro zu überwachendes Feld was in ein FieldObjekt (Name, Inhalt, etc.)
- Beim Speichern schreibt man zusätzlich die neuen Werte in die FieldObjekte und lässt sich die Unterschiede geben.

aha. von alleine draufgekommen. sehr schön.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 07.07.04 - 23:56:19
Vielen Dank, Thomas, für Deine Erklärung.

Habe es soweit glaub ich verstanden (incl. Reihenfolge, die ja easy über das Array der Field-Objekte gelöst wird).

Ich werde mal versuchen, das soweit selber hinzubekommen.
Dabei werde ich aber ein Ctrl+N im Client machen - also wohl nochmal neu anfangen mit den Klassen (da fällt mir das glaub ich leichter).
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 10.07.04 - 16:13:47
Ich hab jetzt mal die Klasse "HistoryField" neu erstellt. Ich glaube hier brauchts gar keine Auftrennung Abstrakte Klasse / Unterklassen. Aber bestimmt noch an anderer Stelle der History-Klassen.

Code
Public Class HistoryField
   Private m_itmField As NotesItem
   Private m_strFieldTitle As String
   Private m_vInitialValue As Variant
   Private m_vNewValue As Variant   
   '-------------------------------------------------------------------------------------------------
   Public Sub new(itmField As NotesItem, strItemTitle As String)
      Dim iItemType As Integer      
      'Das Item und den Item-Titel in die Membervariable
      Set m_itmField = itmField
      m_strFieldTitle = strItemTitle
      '----> Den Iteminhalt auslesen
      m_vInitialValue = GetFieldValue()
      '<----
   End Sub
   '-------------------------------------------------------------------------------------------------
   Public Sub setInitialValue()
      'Setzt den aktuellen Feldinhalt als InitialValue. Vielleicht brauchen wir
      'das irgendwann einmal :-)
      m_vInitialValue = GetFieldValue() 
   End Sub
   '-------------------------------------------------------------------------------------------------
   '########################################################   
   'Get/Set-Methoden
   '-------------------------------------------------------------------------------------------------
   Public Property Get difference As String
      Dim strDiff As String      
      Dim iItemType As Integer
      
      'Der neue Iteminhalt
      m_vNewValue = GetFieldValue()
      
      '---> Item-Typ      
      On Error 91 Goto OBJECTNOTSET   'If it is a new doc and field is RTF
      iItemType = m_itmField.Type
      On Error Goto 0   'Fehlerbehandlungsroutine wieder zurücksetzen
      '<---
      
      Select Case iItemType
      Case RICHTEXT:
         If m_vInitialValue = m_vNewValue Then
            'Keine Feldänderung            
            strDiff = ""
         Else
            'Feldinhalt hat sich geändert
            strDiff = "Changed Richtext-Field '" & m_strFieldTitle & "'"            
         End If
      Case Else:
         m_vNewValue = m_itmField.Values
         If m_vInitialValue = m_vNewValue Then
            'Keine Feldänderung                        
            strDiff = ""
         Else
            'Feldinhalt hat sich geändert
            strDiff =    AuxImplode(m_vInitialValue, " / ") 'erstmal alles in ein String   
            strDiff = AuxRemoveLinebrakes(strDiff, " ")
            strDiff = "Changed Field '" & m_strFieldTitle & "' (former value: '" & strDiff & "')"
         End If
      End Select 'Case iItemType
      
      difference = strDiff
      
EXITSCRIPT:
      Exit Property
OBJECTNOTSET:      
      iItemType = RICHTEXT
      Resume Next
   End Property
   '########################################################
   '-------------------------------------------------------------------------------------------------   
   Private Function GetFieldValue() As Variant      
      'Den Item-Inhalt bzw. bei RTF Datum letzter Änderung auslesen .........
      Dim iItemType As Integer
      
      '-> Item-Typ      
      On Error 91 Goto OBJECTNOTSET   'If it is a new doc and field is RTF
      iItemType = m_itmField.Type
      On Error Goto 0   'Fehlerbehandlungsroutine wieder zurücksetzen
      '<-
      Select Case iItemType
      Case RICHTEXT:      
         GetFieldValue = m_itmField.LastModified
      Case Else:
         GetFieldValue = m_itmField.Values
      End Select
      '<----
EXITSCRIPT:
      Exit Function
OBJECTNOTSET:      
      GetFieldValue = "NEWRTF"
      Resume EXITSCRIPT   
   End Function
   '-------------------------------------------------------------------------------------------------   
   
   
End Class

Mit dem Rest mache ich noch gelegentlich weiter...

*Edit*
Hier hab ich noch die Klasse beschrieben:
(http://www.atnotes.de/attachments/klassenbeschr_02.gif)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 10.07.04 - 17:41:19
Ich glaube hier brauchts gar keine Auftrennung Abstrakte Klasse / Unterklassen.

nun ja, du hast diese Aufteilung in der Klasse gemacht. In mehreren Methoden sogar.
Lass da mal, rein theoretisch, noch ein paar Fälle dazu kommen. Dann wirds unangenehm.
Also: eine weitere Feldart kommt dazu. Du musst Änderungen an deiner Klasse machen und diese Klasse für alle Feldarten nochmal testen (kann ja sein, dass da was schiefgelaufen ist).

Wenn du die Unterscheidung durch verschiedene Subklassen machst, dann siehts so aus:
Neue Klasse, Funktionalität implementieren (musst du ja bei der ARt, die du gewählt hast, auch), diese (und nur diese) Klasse testen. Die bereits funktionierenden Klassen werden nicht angerührt.
Das ist nur ein Vorteil.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 10.07.04 - 17:48:58
Stimmt, Thomas  ::)

Allerdings macht es dann wohl nicht Sinn, mit einer abstrakten Klasse zu arbeiten, oder?

Ich will die Entscheidung, um welches Feld es sich handelt nicht der Routine überlassen, die das Feld-Objekt erstellt. Somit fällt wohl das Konstrukt
(http://www.atnotes.de/attachments/snapfield.gif)
aus.

Ergo erstelle ich ein Objekt, und das Objekt muss dann je nach Feldtyp (Text, RTF, Datum etc.) entsprechendes machen und mir mit Call Field.difference den Unterschied geben.

Wie würdest Du das machen? Gleich im Konstruktor eine Select Case einbauen und dann je nach Feldtyp entsprechende Field-Text/RTF/Datum etc. - Objekte erzeugen?
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 10.07.04 - 17:58:53
das macht üblicherweise eine sog. Factory.

Das ist eine Klasse, deren einzige Aufgabe es ist, Objekte zu erzeugen.

So in der Art:

Class FieldFactory

   Public Function getInstance(item As NotesItem) As HistoryField
      Select Case item.Type
         Case 1
            Set getInstance = New RTHistoryField()
         Case Else
            REM your code goes here
      End Select
   End Function

End Class
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 10.07.04 - 18:12:14
Danke Thomas, die Fabrik ist wohl genau das was wir hier brauchen  :)

Hab aber noch ein paar Fragen:

* Wie würde ein UML-Diagramm hierzu aussehen ? (habe im Index von Oestereich's Buch [OO SW-Entwicklung] nix gefunden zu Factory)
* Was macht dann die HistoryField Klasse überhaupt noch?
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 10.07.04 - 18:24:15
du musst in das bisherige UML DIagramm nur noch die Factory-Klasse dazu malen. Sie hat keine Assoziationen zu anderen Klassen.

Die Feld-Klassen tun das Gleiche, was sie jetzt auch tun: Unterschiede vergleichen und dem Aufrufer zurückgeben.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 10.07.04 - 18:33:12
Factory ist ein "Design Pattern".
Schlaue Leute haben bemerkt, dass manche Probleme beim SW-Design immer wieder kehren und haben dafür allgemeingültige oo Lösungen zusammengefasst - die Design Patterns.
Standardbuch dazu ist das hier: http://www.amazon.de/exec/obidos/ASIN/3827318629/ref=lpr_g_1/302-7117918-1136836 (http://www.amazon.de/exec/obidos/ASIN/3827318629/ref=lpr_g_1/302-7117918-1136836)
Ok, das ist die deutsche Version, Original ist in Englisch geschrieben. Ist wohl ein Buch für etwas Fortgeschrittene. Kann aber auch einem weniger Fortgeschrittenem nix schaden. Im Gegenteil.
Es gibt auch Analyse-Muster. Für immer widerkehrende Probleme, auf die du in der Analyse triffst (hier drin sind unter Anderem ein paar beschrieben: http://www.amazon.de/exec/obidos/ASIN/3827402859/qid=1089476915/sr=2-1/ref=sr_2_11_1/302-7117918-1136836 (http://www.amazon.de/exec/obidos/ASIN/3827402859/qid=1089476915/sr=2-1/ref=sr_2_11_1/302-7117918-1136836))
Das habe ich glaube ich schonmal empfohlen. Das ist ein gutes Lehrbuch. Hat sogar mir bis über die Mitte des Buchs hinaus gefallen.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 10.07.04 - 18:55:19
Danke, aber was ich hier nicht kapiere:

Public Function getInstance(item As NotesItem) As HistoryField

Ich sehe da eine Factory, die sozusagen übergeordnet mir ein Haufen Objekte erstellt.

Den Aufruf hätt ich mir jetzt so gedacht:

Class FieldFactory
   Private m_HistoryFieldRT as RTHistoryFieldRT
   Private m_HistoryFieldText as RTHistoryFieldText
   Private m_HistoryFieldDatum as RTHistoryFieldDatum

  Sub new(item As NotesItem)
      Select Case item.Type
        Case 1:
            Set m_HistoryFieldRT = New RTHistoryFieldRT(item)
        Case Else:
            Set m_HistoryFieldText = New m_HistoryFieldText(item)
      End Select
  End Sub

End Class

Warum macht man / machst Du das über eine Function? Warum steht da "As HistoryField" ?
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 10.07.04 - 19:19:33
schwierig zu erklären (weil das im Moment für mich offensichtlich ist und ich mir diese Frage noch nie gestellt habe)

naja, was für ein Objekt brauchst du denn?
eine Instanz der Klasse HistoryField bzw. einer Subklasse davon.
von dem möchtest du ja dann mal die Unterschiede erfragen.
deshalb lassen wir uns von der Factory eins geben und arbeiten damit weiter.

es gibt nur ein einziges Factory-Objekt.
aber viele HistoryField-Objekte.
die Factory hat wirklich nur die Aufgabe, Objekte zu erzeugen und dem Aufrufer zurückzugeben.
Eine Factory nimmst du, damit das Wissen, unter welchen Umständen welches HistoryField-Objekt erzeugt werden muss, an einer Stelle ist.
Du hast ja schon erkannt, dass es evtl. nicht so geschickt ist, dieses Wissen auch noch in die History-Klasse zu packen bzw. dass es logisch gesehen nicht dort hingehört.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 10.07.04 - 19:37:58
Sorry, checke es noch überhaupt nicht.

Zitat
es gibt nur ein einziges Factory-Objekt.
aber viele HistoryField-Objekte.

Vielleicht macht es das einfacher:
Mit welchem Code würdest Du den das Factory-Objekt erzeugen?

Rufst Du dann n mal die Public Function getInstance auf?

Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 10.07.04 - 19:42:28
Ja genau.

Anstelle des
Set oHistoryFeld = New RTHistoryFeld(item)

das du jetzt machst,

machst du

Set oHistoryFeld = oFactory.getInstance(item)

vorher musst du einmal die Factory erstellen.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 10.07.04 - 20:07:59
Verstehe es noch nicht:

Wir haben hier das History-Objekt (gibt’s nur einmal).
Das History-Objekt erzeugen wir beim Öffnen des Dokumentes (PostOpen).

Im Konstruktor (sub new()) des HistoryObjektes
 - machen wir ein Set HistoryFactory = New HistoryFactory()
 - Pro Feld machen wir ein “HistoryFactory.getInstance(item(i))”

Dann hab ich jetzt meine Objekte erzeugt.

War es das was Du meintest?
Ich habe doch damit gar nicht meine HistoryField - Objekte in einem Array?

Ich sehe wohl den Wald vor lauter Bäumen nicht....
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 10.07.04 - 20:52:35
die Objekte musst du selber noch in das Array packen.
In einer Schleife (die, die du schon vorher benutzt hast, um die Objekte zu erzeugen)
In der History-Klasse.
Wenn du den Code der History-Klasse postest, kann ich dir zeigen wo.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 11.07.04 - 15:41:35
Wenn du den Code der History-Klasse postest, kann ich dir zeigen wo.

Prima, ich mach erstmal die Klassen alle fertig und poste dann den Code bzw. die nsf ....
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 11.07.04 - 17:54:31
OK, habe den aktuellen Stand angehängt.
Aufgrund des R5-Debug-Problems entwickle ich das jetzt in ND6 (versuche aber R5-kompatibel zu bleiben).

Hier noch die HistoryMain-Klasse als Code:
Code
'HistoryMainClass:

Option Declare
'--------------------------------------------------------------------
Use "HistoryAuxiliaryRoutines"
Use "HistoryFieldClass"
Use "HistoryEntryClass"
'--------------------------------------------------------------------
'Konstanten
Const MAX_SIZE# = 5000 'Maximale Größe in Bytes des History-Feldes
Const FIELDNAME_HISTORY$ = "History"  'Feldname des History-Feldes
'--------------------------------------------------------------------
Public Class HistoryMain

   Private m_doc As NotesDocument
   Private m_strHistoryFieldNames As String
   Private m_vaHistoryFieldNames As Variant
   Private m_strHistoryFieldTitles As String
   Private m_vaHistoryFieldTitles As Variant
   Private m_iHistoryFieldAmount As Integer 'Anzahl zu überwachender Felder
   Private m_iMaxEntryAmount As Integer
   Private m_strTextNew As String
   Private m_HistoryFields() As HistoryField
   Private m_strDifferences() As String
   Private m_strHistoryFieldname As String
   '--> Klasse 'HistoryEntry'
   Private m_HistoryEntry As HistoryEntry 'Neuer Eintrag
   Private m_HistoryEntries() As HistoryEntry 'Array aller History-Einträge
   Private m_EntryCount As Integer 'Anzahl der Einträge des HistoryFeldes
   '<---

   '-------------------------------------------------------------------------------------------------------------------------
   Public Sub new(doc As NotesDocument, strHistoryFieldNames As String, strHistoryFieldTitles As String, iMaxEntryAmount As Integer, strTextNew As String)
      Dim iLB As Integer
      Dim iUB As Integer

      '---> Setze Membervariablen
      Set m_doc = doc
      m_strHistoryFieldNames = strHistoryFieldNames
      m_strHistoryFieldTitles = strHistoryFieldTitles
      m_iMaxEntryAmount = iMaxEntryAmount
      m_strTextNew = strTextNew
      '<---

      '---> Die zu prüfenden Felder ermitteln
      m_vaHistoryFieldNames = AuxExplode(m_strHistoryFieldNames, "##")
      m_vaHistoryFieldTitles = AuxExplode(m_strHistoryFieldTitles, "##")
      'Prüfen ob beide Arrays die gleiche Anzahl an Einträgen haben; falls nicht werden als Titel die Feldnamen übernommen.
      iLB = Lbound(m_vaHistoryFieldNames) - Lbound(m_vaHistoryFieldTitles)
      iUB = Ubound(m_vaHistoryFieldNames) - Ubound(m_vaHistoryFieldTitles)
      If (iLB <> 0) Or (iUB <> 0) Then
         m_vaHistoryFieldTitles = m_vaHistoryFieldNames
      End If
      'Ermitteln der Anzahl zu überwachender Felder
      m_iHistoryFieldAmount = Ubound(m_vaHistoryFieldNames) - Lbound(m_vaHistoryFieldNames) + 1
      'So, nun haben wir:
      '                      m_vaHistoryFieldNames = die zu überwachenden Item-Namen in Array
      '                      m_vaHistoryFieldTitles = die Titel der Felder
      '                      m_iHistoryFieldAmount = die Anzahl der Felder
      '<---

      'Erstellen der HistoryField - Objekte in einem Array
      Call initHistoryFields()
      'Nun erzeugen wir noch die HistoryEntry-Objekte. Pro bisherigen Eintrag im History-Feld erzeugen wir 1 HistoryEntryObjekt
      Call initHistoryEntries()
   End Sub
   '-------------------------------------------------------------------------------------------------------------------------
   Private Sub initHistoryFields()
      'Erstellen der HistoryField - Objekte in einem Array
      Dim itmField As NotesItem
      Dim i As Integer
      For i = 0 To m_iHistoryFieldAmount - 1
         Set itmField = m_doc.GetFirstItem(m_vaHistoryFieldNames(i))
         Redim Preserve m_HistoryFields(i)
         Set m_HistoryFields(i) = New HistoryField(itmField, m_vaHistoryFieldTitles(i))
      Next
   End Sub
   '-------------------------------------------------------------------------------------------------------------------------
   Private Sub initHistoryEntries()
      'Erstellt HistoryEntry - Objekte. Pro History-Eintrag wird ein HistoryEntry-Objekt erzeugt
      'Ergebnis steht im Array  'm_HistoryEntries'
      Dim Entry As HistoryEntry
      Dim iContinue As Integer
      m_EntryCount = 0

      iContinue = True
      Do
         Set Entry = New HistoryEntry
         Call Entry.readFromDoc(m_doc, m_EntryCount)
         If Entry.size > 0 Then
            Redim Preserve m_HistoryEntries(m_EntryCount)
            Set m_HistoryEntries(m_EntryCount) = Entry
            m_EntryCount = m_EntryCount + 1
         Else
            iContinue = False
         End If
      Loop While (iContinue = True)
   End Sub
   '-------------------------------------------------------------------------------------------------------------------------
   Public Sub save()
      'Wir schreiben hier die Änderungen in das History-Feld
      '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      'Änderungen in das Array 'm_strDifferences'
      Call getHistoryDifferences()

      'History schreiben
      If Not (m_strDifferences(0) = "NOCHANGES") Then  'History nur schreiben wenn Änderungen stattgefunden haben
         Call writeHistory()
         Call m_doc.Save(True, True)
      End If

      'Aufräumen und neu initiieren
      Call CleanupAndInitiate()

   End Sub
   '-------------------------------------------------------------------------------------------------------------------------
   Private Sub getHistoryDifferences()
      Dim i As Integer
      Dim iCount As Integer
      Dim strDifference As String

      If m_doc.IsNewNote Then 'Falls es sich um ein neues Doc handelt
         Redim m_strDifferences(0)
         m_strDifferences(0) = m_strTextNew
         Exit Sub
      End If

      'Wir bekommen die Unterschiede in das Array "m_strDifferences"
      iCount = -1
      For i = 0 To m_iHistoryFieldAmount - 1
         strDifference = m_HistoryFields(i).difference
         If Not strDifference = "" Then
            iCount = iCount + 1
            Redim Preserve m_strDifferences(iCount)
            m_strDifferences(iCount) = strDifference
         End If
      Next
      If iCount = -1 Then 'Es gab keine Unterschiede
         Redim m_strDifferences(0)
         m_strDifferences(0) = "NOCHANGES" 'Es gab keine Änderung !
      End If

      'Nun stehen die Änderungen in "m_strDifferences"
   End Sub
   '-------------------------------------------------------------------------------------------------------------------------
   Private Sub writeHistory()

      'Klasse für Historyeintrag
      Set m_HistoryEntry = New HistoryEntry
      Redim Preserve m_HistoryEntries(m_EntryCount)
      Set m_HistoryEntries(m_EntryCount) = m_HistoryEntry
      m_EntryCount = m_EntryCount + 1


     'Werte vergleichen und Ergebnisse an den HistoryEntry geben
      m_HistoryEntry.Action = m_strDifferences

      Dim nHowManyEntries As Integer
      Dim nStart As Integer
      Dim i As Integer

      Call clear()

      nHowManyEntries = getMaxEntries()

      nStart = (Ubound(m_HistoryEntries)+1) - nHowManyEntries
      For i = nStart To Ubound(m_HistoryEntries)
            'History-Eintrag ins Dokument schreiben
         Set m_HistoryEntry = m_HistoryEntries(i)
         Call m_HistoryEntry.write(m_doc)
      Next

   End Sub
   '-------------------------------------------------------------------------------------------------------------------------
   Private Sub clear()
      Call m_doc.ReplaceItemValue(FIELDNAME_HISTORY, "")
   End Sub
   '-------------------------------------------------------------------------------------------------------------------------
   Private Function getMaxEntries() As Integer
      Dim i As Integer
      Dim entry As HistoryEntry
      Dim iTotalSize As Integer
      getMaxEntries = 0

      For i = Ubound(m_HistoryEntries) To Lbound(m_HistoryEntries) Step -1
         Set entry = m_HistoryEntries(i)
         iTotalSize = iTotalSize + entry.size
         If iTotalSize > MAX_SIZE Then
            Msgbox "Maximal erlaubte Größe in Bytes (" & Cstr(MAX_SIZE) & ") wurde überschritten"
            Exit For 'Exit Function
         End If
         getMaxEntries = getMaxEntries + 1
      Next
      'Nun prüfen wir ob die Anzahl erlaubter Einträge dadurch nicht überschritten wird
      If   getMaxEntries > m_iMaxEntryAmount Then
         Print "Max. Anzahl Einträge (" & Cstr(m_iMaxEntryAmount) & ") wurde überschritten"
         getMaxEntries = m_iMaxEntryAmount
      End If
   End Function
   '-------------------------------------------------------------------------------------------------------------------------
   Private Sub CleanupAndInitiate()
   'Neue Werte in als InitialValue schreiben, für den Fall dass erneut gespeichert wird
      Dim i As Integer
      For i = 0 To m_iHistoryFieldAmount - 1
         Call m_HistoryFields(i).setInitialValue
      Next

   'HistoryEntries neu initiieren
      Erase m_HistoryEntries
      Call initHistoryEntries()

   End Sub
   '-------------------------------------------------------------------------------------------------------------------------
End Class
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 11.07.04 - 18:43:56
Hier noch das aktuelle UML-Diagramm (-> ist-Stand):
(http://www.atnotes.de/attachments/historyclass_101.gif)

Und so - oder so ähnlich - glaub ich sollte das dann mal ausschauen (rechts sind die methods und properties noch nicht gefüllt):

(http://217.160.137.156/user/bp/tmc/_threaduploads/history/historyclass_102.gif)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 11.07.04 - 19:53:17
in dem Link, den du im Tipps Bereich gepostet hast
(http://www.lotusgeek.com/SapphireOak/LotusGeekBlog.nsf/plinks/ROLR-5UV6YM (http://www.lotusgeek.com/SapphireOak/LotusGeekBlog.nsf/plinks/ROLR-5UV6YM))
da ist ein Posting von mir, dass zeigt, wie du das machen kannst.
Da sind zwei Klassen (AbstractImportFactory und ExcelFactory).
In der AbstractImportFactory ist die Methode init(), allerdings nur die Signatur.
In der Excel Factory gibts die Methode auch, hier ist die wirkliche Funktionalität implementiert.

Ich hab den Code von Dir mal in eine ND6 - DB kopiert zur besseren Übersicht.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 12.07.04 - 22:09:47
Habe gerade noch einen Bug in der history_06.nsf entdeckt:

Wird ein Zahlenfeld zur Überwachung herangezogen, und man speichert das Dok 1mal, ändert danach das Zahlenfeld aber nicht und macht erneut Ctrl+s, dann wird immer und immer wieder eine Zeile geschrieben, dass sich Zahlenfeld geändert.
Die unterstützende Function "AuxCompareValues" hab ich schon getestet, die erkennt zuverlässig Unterschiede auch von Zahlenfeldern. Muss also an was anderem liegen.....
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 16.07.04 - 20:03:38
** Update **

+ Bug entfernt (Zahlenfelder)

+ Klassen teilweise dokumentiert (siehe View "Class Documentation")

+ Zu überwachende Felder werden als String-Array übergeben

+ Erweiterung der History-Klasse
   -> Nun können auch manuell Einträge hinzugefügt werden (z.B. über Workflow-
       anwendung)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 16.07.04 - 20:16:22
kann ich leider im Moment net bestaunen. Hab kein Notes zur Hand.
Sobald ich kann, gebe ich Feedback.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 16.07.04 - 20:20:42
Sobald ich kann, gebe ich Feedback.

OK, prima.

Ich habe mittlerweile das Gefühl, dass die "HistoryMain" - Klasse viel zu aufgebläht ist. Vielleicht sollte man die nochmal auftrennen.

Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: -Michael- am 17.07.04 - 22:06:10
Ich habe mal versucht, Eurem Thread ansatzweise zu folgen. (obwohl dies mehr überflogen war aufgrund 10 Seiten Thread).

Was mir aufgefallen ist:

Eigentlich ist ein Objekt immer klar.

Ein Flugzeug ist eben ein Flugzeug.
Ein Auto ein Auto.

Das HistoryMain - Objekt (zumindest lt. dem obigen Code) ist als Objekt nicht mehr transparent für mich.

Was genau ist ein HistoryMain-Objekt? Was ist es im Vergleich zu einem Auto?

Aber ich will Euch hier nicht weiter stören..... Ist mir halt nur als "Außenstehenden" so aufgefallen. Die HistoryField-Klasse und die HistoryEntry-Klasse ist mir klar und wurde auch entsprechend sauber abgegrenzt definiert.

Michael
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: Semeaphoros am 18.07.04 - 08:25:33
Au Michael, wie wäre die Welt schön, wenn Deine Behauptung stimmte:

Zitat
Eigentlich ist ein Objekt immer klar.

In der Praxis ist genau das eines der grössten Probleme: die genaue und logische Abgrenzung der Objekte untereinander. Beispiel, das mal von einem Hörer in einem meiner Vorträge aufgebracht wurde: Eingabevalidierungen: gehören die jetzt in die Frontend-Klasse oder in die Backend-Klasse?

Tja, lässt sich nicht allgemein beantworten. Die Sicherstellung der Datenkonsistenz (wovon die Validierung ein Teil ist) gehört ins Backend spätestens dann, wenn neben der direkten Eingabe auch andere Datenquellen wie Import in Frage kommen. Hingegen das Mitteilen eines fehlenden/falschen Wertes ist Sache des Frontends, schlimmstenfalls muss man das  in so einem Fall offensichtlich auf 2 Objekte verteitlen - das heisst, wenn man überhaupt dem Objektmodell folgt, so wie es Notes selber vorgibt (man könnte das auch anders machen)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 18.07.04 - 21:03:02
Was genau ist ein HistoryMain-Objekt? Was ist es im Vergleich zu einem Auto?

Aber ich will Euch hier nicht weiter stören..... Ist mir halt nur als "Außenstehenden" so aufgefallen. Die HistoryField-Klasse und die HistoryEntry-Klasse ist mir klar und wurde auch entsprechend sauber abgegrenzt definiert.

Du störst nicht.

vielleicht kannst du mit folgender Analogie was anfangen:

HistoryMain zu HistoryEntry - Klasse verhält sich so wie eine Liste zu ihren Einträgen (z.B. Rechnung - Rechnungsposition)

Hilft das schon?
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: koehlerbv am 18.07.04 - 21:11:41
Oder - um bei Deiner Analogie zu bleiben, Michi: HistoryMain ist "Fortbewegungsmittel", HistoryEntry wäre dann "Auto".
Und ein Auto ist ein Auto und ein Fortbewegungsmittel.

Cu koFr (hoffentlich),
Bernhard
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: -Michael- am 18.07.04 - 21:57:34
vielleicht kannst du mit folgender Analogie was anfangen:

HistoryMain zu HistoryEntry - Klasse verhält sich so wie eine Liste zu ihren Einträgen (z.B. Rechnung - Rechnungsposition)

Hilft das schon?

Danke, das erklärt einiges.

@Bernhard: Deine Erklärung bestätigt mir das, danke.
Schön dass Du mal wieder bei uns vorbeischaust  ;)
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: -Michael- am 18.07.04 - 22:06:11
Au Michael, wie wäre die Welt schön, wenn Deine Behauptung stimmte:

Zitat
Eigentlich ist ein Objekt immer klar.

Stimmt wohl was Du sagst. Es fehlte mir als Außenstehenden auch etwas der Zusammenhang. Wobei: Ein Blick auf die UML-Diagramme hätte mir die Zusammenhänge gezeigt....

Jedenfalls bin ich froh darüber, dass es diesen Thread hier gibt. Ich werde versuchen den weiter (zumindest passiv) zu verfolgen - gerade Dinge wie abstrakte Klassen, Factory-Klassen etc. finde ich sehr interessant.

Michael
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: Semeaphoros am 18.07.04 - 23:10:38
Stimmt, Matthias und Thomas haben hier einen sehr lebendigen und instruktiven Thread zusammen aufgebaut.
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: animate am 19.07.04 - 09:51:11
Oder - um bei Deiner Analogie zu bleiben, Michi: HistoryMain ist "Fortbewegungsmittel", HistoryEntry wäre dann "Auto".
Und ein Auto ist ein Auto und ein Fortbewegungsmittel.

*hüstel*

das ist nicht ganz richtig. Zwischen HistoryMain und HistoryEntry besteht eine Beziehung, aber keine "ist ein", sondern eine "besteht aus"-Beziehung.

Analogie mit Autos könnte sein:

HistoryMain => Parkplatz (hi-tec)
HistoryEntry => Auto
Titel: Re:Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 30.07.04 - 20:51:58
*** nach oben ***
Vielleicht hat noch wer Lust hier mitzuwirken....
Titel: Re: Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: wuwu am 10.11.04 - 08:10:28
hallo tmc,

habe mich nun durch den thread durchgehandelt, habe auch so einiges gelesen, die aktuelle history 7 geluscht.

wie baue ich das genaze jetzt in einer db von mir ein?
wo mus ich welchen code wie einfügen und wo kann ich die felder definieren die überwacht werden sollten?

danke für die hilfe!

mfg horst
Titel: Re: Wie kann ich eine Klasse sinnvoll aufbauen ?
Beitrag von: TMC am 10.11.04 - 20:08:45
Horst, bau doch das ganze anhand einer der geposteten Beispieldatenbanken auf.
Einbauen solltest Du das nirgends ohne ausgiebiger Tests, sind bestimmt noch einige Bugs enthalten. Mit Sicherheit nix für eine Produktivdatenbank zum momentanen Stand !

Matthias

**Edit**
Du kannst Dir auch dies hier mal ansehen: http://www.atnotes.de/index.php?topic=18601.0