Benutzer mit den meisten Antworten
Geschäftslogik von der Präsentationsschicht trennen

Frage
-
Hallo,
ich habe eine Frage zum o.g. Thema. Ich habe mein Formular mit einigen Methoden wie unten im Code schematisch dargestellt:
Public Class Form1 ' code Private Sub Method1() If Method2() Then ' code End If Me.TextBox1.Text &= "blabla1" & vbCrLf ' code Method3() Me.TextBox1.Text &= "blabla2" & vbCrLf End Sub Private Shared Function Method2() As Boolean Dim var As Boolean = False ' code Return var End Function Private Shared Sub Method3() ' code End Sub End Class
Ich möchte nun die Methoden in eine eigene Klasse packen. Mein Problem ist, dass ich nicht weiss, wie ich Methode1 modifizieren muss, damit ich sie zusammen mit Methode2 und Methode3 in eine eigenständige Klasse packen kann. Methode1 greift ja auf die Textbox von Form1 zu. Muss ich dafür ein Interface definieren oder geht es über Events? Für die Profis unter euch dürfte die Frage leicht zu beantworten sein.
Schönen Gruß,
LittleBlueBird
Antworten
-
Hallo LittleBlueBird,
Du kannst z.B. ein Event benutzen, um Daten von einer Klasse in die andere zu transportieren.
Ich habe das mal skizziert. Hoffentlich entspricht das Deinen Vorstellungen. (Beachte auch die Zugriffsmodihikatoren)
Public Class Form1 Private WithEvents myMethods As New divMethods Private Sub writeToBox(ByVal msg As String) Handles myMethods.upDateBox Me.TextBox1.Text &= msg End Sub Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Me.myMethods.Method1() End Sub End Class Public Class divMethods Public Event upDateBox(ByVal msg As String) Friend Sub Method1() If Method2() Then ' code End If RaiseEvent upDateBox("blabla1" & vbCrLf) ' code Method3() RaiseEvent upDateBox("blabla2" & vbCrLf) End Sub Private Shared Function Method2() As Boolean Dim var As Boolean = False ' code Return var End Function Private Shared Sub Method3() ' code End Sub End Class
Man könnte das auch mit Property erledigen. Nur dann müsste man im Konstruktor von der Klasse divMethods die Instanz von Form1 übergeben. Dann kann man darüber wieder auf ein property von Form1 zugreifen, welches die Daten in die Textbox schreibt.
Gruss Ellen
Ich benutze/ I'm using VB2008 & VB2010
- Bearbeitet Ellen Ramcke Montag, 9. Juli 2012 11:13
- Als Antwort markiert LittleBlueBird Montag, 9. Juli 2012 19:37
Alle Antworten
-
Hallo LittleBlueBird,
Du kannst z.B. ein Event benutzen, um Daten von einer Klasse in die andere zu transportieren.
Ich habe das mal skizziert. Hoffentlich entspricht das Deinen Vorstellungen. (Beachte auch die Zugriffsmodihikatoren)
Public Class Form1 Private WithEvents myMethods As New divMethods Private Sub writeToBox(ByVal msg As String) Handles myMethods.upDateBox Me.TextBox1.Text &= msg End Sub Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Me.myMethods.Method1() End Sub End Class Public Class divMethods Public Event upDateBox(ByVal msg As String) Friend Sub Method1() If Method2() Then ' code End If RaiseEvent upDateBox("blabla1" & vbCrLf) ' code Method3() RaiseEvent upDateBox("blabla2" & vbCrLf) End Sub Private Shared Function Method2() As Boolean Dim var As Boolean = False ' code Return var End Function Private Shared Sub Method3() ' code End Sub End Class
Man könnte das auch mit Property erledigen. Nur dann müsste man im Konstruktor von der Klasse divMethods die Instanz von Form1 übergeben. Dann kann man darüber wieder auf ein property von Form1 zugreifen, welches die Daten in die Textbox schreibt.
Gruss Ellen
Ich benutze/ I'm using VB2008 & VB2010
- Bearbeitet Ellen Ramcke Montag, 9. Juli 2012 11:13
- Als Antwort markiert LittleBlueBird Montag, 9. Juli 2012 19:37
-
Hallo Ellen,
vielen Dank für die Lösung und insbesondere für den Code. Du hast mir damit sehr geholfen. Ich werde dein Beispiel implementieren, da die Möglichkeit mit den Eigenschaften meines Erachtens nicht so elegant ist, wobei sie durchaus performanter sein kann.
Schöne Grüße,
LittleBlueBird
-
Hallo Ellen,
vielen Dank für die Lösung und insbesondere für den Code. Du hast mir damit sehr geholfen. Ich werde dein Beispiel implementieren, da die Möglichkeit mit den Eigenschaften meines Erachtens nicht so elegant ist, wobei sie durchaus performanter sein kann.
Schöne Grüße,
LittleBlueBird
Hallo LittleBlueBird,
das freut mich sehr.
Ich schwebe gerade auf Wolke 7. Mein neuer Rechner heute gekauft: HP OMMI27 1000eg. Das ist sowas von schick:-)
Gruss Ellen
Ich benutze/ I'm using VB2008 & VB2010
-
Hallo Ellen,
dann wünsche ich dir viel Vergnügen mit dem neuen All-in-One Rechner. Sieht in der Tat schick aus, wobei ich mich frage, wo da die Laufwerke (Festplatte, DVD) untergebracht sind? Bei 27" Bildschirmdiagonale kannst du ihn sogar als Fernseher verwenden ;-)
Ich habe noch eine Frage im Zusammenhang mit deinem Beispiel. Ich habe im Internet ein ähnliches Konstrukt gesehen, da wurden jedoch Delegaten verwendet. Dein Beispiel würde also wie folgt aussehen:
Public Delegate Sub UpdateMessageHandler(msg As String) Public Class DivMethods Public Event Message As UpdateMessageHandler Private Sub UpdateMessage(msg As String) RaiseEvent Message(msg) End Sub Friend Sub Method1() If Method2() Then ' code End If UpdateMessage("blabla1" & vbCrLf) ' code Method3() UpdateMessage("blabla2" & vbCrLf) End Sub Private Shared Function Method2() As Boolean Dim var As Boolean = False ' code Return var End Function Private Shared Sub Method3() ' code End Sub End Class
Weisst du zufällig, ob es bei der Verwendung von Delegaten einen Vorteil gibt?
Schöne Grüße,
LittleBlueBird
-
Hallo Ellen,
dann wünsche ich dir viel Vergnügen mit dem neuen All-in-One Rechner. Sieht in der Tat schick aus, wobei ich mich frage, wo da die Laufwerke (Festplatte, DVD) untergebracht sind? Bei 27" Bildschirmdiagonale kannst du ihn sogar als Fernseher verwenden ;-)
Ich habe noch eine Frage im Zusammenhang mit deinem Beispiel. Ich habe im Internet ein ähnliches Konstrukt gesehen, da wurden jedoch Delegaten verwendet. Dein Beispiel würde also wie folgt aussehen:
Public Delegate Sub UpdateMessageHandler(msg As String) Public Class DivMethods Public Event Message As UpdateMessageHandler Private Sub UpdateMessage(msg As String) RaiseEvent Message(msg) End Sub Friend Sub Method1() If Method2() Then ' code End If UpdateMessage("blabla1" & vbCrLf) ' code Method3() UpdateMessage("blabla2" & vbCrLf) End Sub Private Shared Function Method2() As Boolean Dim var As Boolean = False ' code Return var End Function Private Shared Sub Method3() ' code End Sub End Class
Weisst du zufällig, ob es bei der Verwendung von Delegaten einen Vorteil gibt?
Schöne Grüße,
LittleBlueBird
Hallo LittleBlueBird,
bei dieser Version wird vorher ein typisierter Funktionszeiger deklariert und damit das Event.
Wo da jetzt der Vorteil ist, das kann ich Dir garnicht sagen. Eigentlich benutzt man so etwas eher für threading.
Gruss Ellen
P.S. Der Rechner ist ja fast ein ein Fernseher. das schmilzt heute alles zusammmen. Festplatte und DVD sind auch im Gehäuse verbaut.
Ich benutze/ I'm using VB2008 & VB2010
-
Hallo LittleBlueBird und Ellen,
Vorteile hat das keinen - und mit Threading hat das nichts zu tun.
Vielmehr hat jemand nur das nachgeahmt, was der VB Compiler ohnehin erzeugt
(und als leiser Verdacht darf aufkeimen, der Code wurde von C# übernommen - ääh übersetzt).Es gilt: Events sind Delegaten - mit zusätzlichen Konventionen, insbesondere was Visual Basic angeht[1]
Visual Basic erstellt aus dem
Public Event upDateBox(ByVal msg As String)
eine Klasse, die so aussehen würde:
' Pseudocode - nicht kompilierbar! Public Class upDateBoxEventHandler Inherits System.MulticastDelegate Public Overridable Sub Invoke(msg As String) ' sowie BeginInvoke, EndInvoke ' der Kürze halber weggelassen End Class
Würde deshalb, weil VB diese Schreibweise nicht erlaubt; ein Erben von [Multicast]Delegate ist nicht zulässig,
das Erzeugen des (richtigen) Codes behält sich Visual Basic hier vor.Diese Klasse wird nun für das Ereignis verwendet, wieder als Pseudocode:
' Pseudocode!
Public Custom Event upDateBox As divMethods.upDateBoxEventHandler AddHandler(value As upDateBoxEventHandler) Me.upDateBoxEvent = CType([Delegate].Combine(Me.upDateBoxEvent, value), divMethods.upDateBoxEventHandler) End AddHandler RemoveHandler(value As upDateBoxEventHandler) Me.upDateBoxEvent = CType([Delegate].Remove(Me.upDateBoxEvent, value), divMethods.upDateBoxEventHandler) End RemoveHandler End Event(Es fehlt ein RaiseEvent, was automatisch erzeugt wird, nur für Custom wäre es wiederum Pflicht).
In der Summe kommt also einiges zusammen, was im Hintergrund erzeugt wird.
Weil vom Einschmelzen bereits die Rede war: Das kann (und sollte) man auch hier tun ;-)
Anstatt jedes Mal einen neuen Delegaten (eine neue Klasse) zu erzeugen,
kann man in solchen Fällen auf die "vorgefertigten" Action Delegaten zurückgreifen
oder falls eine Rückgabe benötigt wird auf einen Func-Delegaten.Ellens Code eingeschmolzen:
Public Class divMethods Public Event upDateBox As Action(Of String) Friend Sub Method1() RaiseEvent upDateBox("blabla1" & vbCrLf) RaiseEvent upDateBox("blabla2" & vbCrLf) End Sub ' Für den Test Friend Shared Sub Run() Dim myMethods As New divMethods AddHandler myMethods.upDateBox, Sub(msg) Console.WriteLine("MyMethod UpdateBox {0}", msg) myMethods.Method1() End Sub End Class
Den Dummycode habe ich weggelassen und Verwendung erfolgt der Kürze in einer Run-Methode.
Gruß Elmar
[1] Durch event wird RaiseEvent freigeschaltet und WithEvents ermöglicht den Einsatz von Handles -
C# z. B. kennt diese Unterscheidung nicht. Aber das wäre ein weiteres Kapitel der Geschichte. -
Hallo Elmar,
danke für die Aufklärung. Da habe ich wieder etwas dazu gelernt. Von Action- und Func-Delegaten hatte ich bisher keine Ahnung. Ich werde mich noch intensiver damit beschäftigen müssen.
Zur Run-Methode habe ich noch einige Fragen:
- Wieso wird die Klasse divMethods nicht über "Private WithEvents ..." instantiiert?
- Weshalb erfolgt die Ereignisbehandlung dynamisch und nicht statisch?
- Wann sollte man Lambda-Ausdrücke verwenden? Ich gebe zu, den Konstrukt Sub(msg) ... noch nicht gekannt zu haben. Nach einiger Recherche habe ich aber herausbekommen, dass es sich um einen Lambda-Ausdruck handelt.
EDIT: Auf Frage 1 habe ich selbst die Antwort gefunden. Du rufst die Run-Methode in der gleichen Klasse auf. Gleichzeitig frage ich mich aber, ob es generell besser ist, die Klasse divMethods in Form1 als "Private WithEvents ..." zu instantiieren. Oder doch lieber local in der Methode, in der ich Method1() aufrufe?
Schöne Grüße,
LittleBlueBird
- Bearbeitet LittleBlueBird Dienstag, 10. Juli 2012 11:09 Ergänzung
-
Hallo LittleBlueBird,
Action und Func sind "vorbereitete" generische Delegaten; funktional sind sie identisch mit einem "selbstgemachten".
1.) WithEvents ist nur notwendig, wenn man Handles verwenden will.
Handles ist funktional mit AddHandler identisch, der Kompiler generiert dabei nur den Code dafür.
Für den Test ist das nicht notwendig Und ich wollte nicht alles wiederholen.
Außerdem kann man WithEvents nur auf Klassenebene verwenden.
Du kannst die Klasse aber ebenso mit Ellens Ursprungsbeispiel verwenden.2.) Ereignisbehandlung muss nicht statisch sein - und typische Button_Click Handles sind es ja auch nicht.
Der Unterschied von statischen (Shared) Methoden zu Instanzmethoden ist,
dass Instanzmethoden der Zugriff auf die Mitglieder (Variablen, Eigenschaften, Methoden)
der umgebenen Klasse möglich ist.
Shared sollte man Methoden kennzeichnen, wenn man diesen Zugriff nicht benötigt,
weil es die Methode unabhängig verwendbar macht[1].
Das ändert sich nicht bei Ereignissen / Delegaten.3.) Verwenden muss man Lambda-Ausdrücke nicht.
Oben schien es mir z. B. angebracht, um das Beispiel kompakter zu halten
(eine Methode hätte man erst wieder suchen müssen und langatmiger wäre es auch gewesen).
Mehr Nutzen bringen sie u. a., wenn man mit lokalen Variablen arbeiten möchte -
in dem Link findest Du einige Beispiele. Wobei dort Action/Func nicht konsequent genutzt wird
und so manches Beispiel unter den Möglichkeiten bleibt
(mag aber Absicht sein, um keinen zu überfordern)Gruß Elmar
[1] verwendet man sehr viele Shared Methoden sollte man seine Einstellung zu OOP prüfen ;-)
-
Hallo Elmar,
danke, dass du dir die Zeit genommen hast, meine Fragen zu beantworten. Ich bedanke mich ebenso für die Links zu den einzelnen Themen.
zu 2) Ich bin davon ausgegangen, dass wenn die Eregnisbehandlung mit AddHandler dynamisch erfolgt, im Gegenzug die Handles-Klausel dann statisch sein muss. Das ist wohl ein Irrtum gewesen.
zu 3) Aus den Beispielen von MSDN entnehme ich, dass Lambda-Ausdrücke meistens dann verwendet werden, wenn es sich um einzeilige bzw. einfache Methoden oder Funktionen handelt.
Ob ich jemals alles lernen werde? Eher unwahrscheinlich! Aber ich gebe nicht auf ;-)
Schöne Grüße,
LittleBlueBird
-
Hallo LittleBlueBird,
Lambda-Ausdrücke können seit Visual Basic 2010 auch mehrzeilig sein,
vorher waren sie auf einzeilige Funktionen beschränkt.[1]Lambdas wird man aber eher für kürzere Methode verwenden,
wird es mehr hat man keine Vorteile mehr zu einer separaten Methode.
Wobei man Methoden generell übersichtlich halten sollte,
Pi * Daumen eine halbe Bildschirmseite - bzw. was man (mit etwas Übung) auf einen Blick erfassen kann;
wird es mehr als eine Seite sollte man nachdenklich werden und den Code vereinfachen oder aufteilen.Wenn man erst mal weiß, dass es Lambdas gibt und sie grundsätzlich verstanden hat,
erkennt man den einen oder anderen Einsatzbereich dafür -
übers Knie brechen muss und sollte man es nicht.Zum Abschluss als Anregung die Klasse noch mal etwas anders:
Public Class divMethods Private _notify As Action(Of String) Public Sub New(notify As Action(Of String)) Me._notify = notify End Sub Friend Sub Method1() DoNotify("blabla1") End Sub Private Sub DoNotify(msg As String) If Me._notify IsNot Nothing Then ' Prüfen auf Nothing, da optional Me._notify(msg) End If End Sub End Class Public Class MainForm ' Zwei Wege mit gleichem Ergebnis Private m1 As New divMethods(AddressOf Benachrichtigung1) Private m2 As New divMethods(Sub(msg) Console.WriteLine("Benachrichtigung 2:" & msg)) Private Sub Benachrichtigung1(msg As String) Console.WriteLine("Benachrichtigung 1:" & msg) End Sub Private Sub executeButton_Click(sender As System.Object, e As System.EventArgs) Handles executeButton.Click m1.Method1() m2.Method1() End Sub End Class
Gruß Elmar
[1] C# kennt bereits seit 2.0 (VS 2005) anonyme (mehrzeilige) Methoden,
und mit 3.0 (VS 2008) wurde die Syntax nochmal deutlich vereinfacht.
Insofern ist man dort länger damit vertraut (und VB hinkte dort lange hinterher). -
Hallo Elmar,
besten Dank für die Erklärung zu den Lambda-Asudrücken und auch für die Anregung. Möglichkeiten scheint es genug zu geben. Dann werde ich die für mich am Besten passende Lösung anwenden. Die Beispiele muss ich unbedingt aufbewahren.
Schönen Gruß,
LittleBlueBird