Objektorientierte Programmierung in VBA: Klassen erstellen
Objektorientiert programmieren in VBA: Klassen, Eigenschaften (Get/Let/Set), Methoden, Ereignisse und Collections am Praxisbeispiel einer Kundenklasse.
Sie kennen VBA-Makros mit Subs und Functions, aber haben Sie schon eigene Klassen erstellt? Objektorientierte Programmierung (OOP) macht VBA-Code wartbarer, wiederverwendbarer und strukturierter. In diesem Beitrag für Fortgeschrittene zeigen wir, wie Sie professionelle Klassen in VBA entwickeln.
Was ist OOP und warum in VBA?
Objektorientierte Programmierung bedeutet: Statt lose Funktionen zu schreiben, erstellen Sie Objekte mit Eigenschaften (Properties) und Methoden.
Beispiel: Kunde ohne OOP (prozedural)
Dim KundenName As String
Dim KundenNummer As Long
Dim KundenRabatt As Double
Sub KundeAnlegen(Name As String, Nummer As Long)
KundenName = Name
KundenNummer = Nummer
End Sub
Sub RabattBerechnen()
If KundenNummer < 1000 Then
KundenRabatt = 0.05
Else
KundenRabatt = 0.1
End If
End Sub
Problem: Nur ein Kunde gleichzeitig, keine Struktur, schwer wartbar.
Mit OOP (objektorientiert)
Dim kunde1 As New Customer
kunde1.Name = "Max Mustermann"
kunde1.Nummer = 1234
Debug.Print kunde1.Rabatt ' → 0.1 (automatisch berechnet!)
Dim kunde2 As New Customer
kunde2.Name = "Anna Schmidt"
kunde2.Nummer = 500
Vorteile:
- Mehrere Kunden gleichzeitig
- Logik gekapselt in der Klasse
- Wiederverwendbar in anderen Projekten
- Einfacher zu testen und debuggen
Erste Klasse erstellen (Class Module)
Schritt 1: Class Module einfügen
- VBA-Editor öffnen (Alt + F11)
- Einfügen → Klassenmodul
- Im Eigenschaftsfenster (F4): Name = “Customer”
Schritt 2: Eigenschaften definieren
' Klassenmodul: Customer
Option Explicit
' Private Variablen (von außen nicht sichtbar)
Private pName As String
Private pNummer As Long
Private pEmail As String
Namenskonvention: Prefix “p” für private Variablen (oder “m_” für “member variable”).
Properties (Get/Let/Set) implementieren
Properties sind kontrollierte Zugriffsmethoden auf private Variablen.
Property Get (Wert lesen)
Public Property Get Name() As String
Name = pName
End Property
Property Let (Wert schreiben, für einfache Datentypen)
Public Property Let Name(ByVal value As String)
' Validierung einbauen!
If Len(value) > 0 Then
pName = value
Else
Err.Raise 5, , "Name darf nicht leer sein!"
End If
End Property
Property Set (für Objektreferenzen)
Private pAdresse As Address
Public Property Set Adresse(ByVal value As Address)
Set pAdresse = value
End Property
Public Property Get Adresse() As Address
Set Adresse = pAdresse
End Property
Regel: Let für Strings/Zahlen/Dates, Set für Objekte (Range, Worksheet, eigene Klassen).
Read-Only Property
Public Property Get Rabatt() As Double
' Automatisch berechnet, kein Let/Set!
If pNummer < 1000 Then
Rabatt = 0.05 ' 5%
Else
Rabatt = 0.1 ' 10%
End If
End Property
Methoden implementieren
Methoden sind Functions oder Subs innerhalb der Klasse.
Public Function BestellungAufgeben(Betrag As Double) As Boolean
' Geschäftslogik
If Betrag <= 0 Then
BestellungAufgeben = False
Exit Function
End If
' Rabatt anwenden
Dim Endpreis As Double
Endpreis = Betrag * (1 - Me.Rabatt)
' Logging
Debug.Print pName & " bestellt für " & Format(Endpreis, "0.00 €")
BestellungAufgeben = True
End Function
Me-Keyword: Verwenden Sie Me.Rabatt statt Rabatt innerhalb der Klasse. Das macht klarer, dass es sich um eine Property handelt.
Initialize und Terminate Events
Diese speziellen Events werden automatisch ausgeführt.
Class_Initialize (Konstruktor)
Private Sub Class_Initialize()
' Wird beim "New Customer" ausgeführt
pNummer = 0
pName = ""
Debug.Print "Neuer Kunde erstellt um " & Now
End Sub
Class_Terminate (Destruktor)
Private Sub Class_Terminate()
' Wird ausgeführt wenn Objekt freigegeben wird
Debug.Print "Kunde " & pName & " wird gelöscht"
' Aufräumen: Datenbankverbindungen schließen, etc.
End Sub
Collections von Objekten
Mit Collections verwalten Sie mehrere Objekte gleichzeitig.
Kunden-Collection erstellen
Sub KundenVerwaltung()
Dim kunden As New Collection
' Kunden hinzufügen
Dim k1 As New Customer
k1.Name = "Max Mustermann"
k1.Nummer = 1001
kunden.Add k1
Dim k2 As New Customer
k2.Name = "Anna Schmidt"
k2.Nummer = 500
kunden.Add k2
' Alle Kunden durchgehen
Dim kunde As Customer
For Each kunde In kunden
Debug.Print kunde.Name & " - Rabatt: " & kunde.Rabatt
Next kunde
End Sub
Collection mit Key (eindeutige ID)
kunden.Add k1, CStr(k1.Nummer) ' Key = Kundennummer
' Später: Zugriff per Key
Dim gefunden As Customer
Set gefunden = kunden("1001")
Debug.Print gefunden.Name ' → "Max Mustermann"
Praxisbeispiel: Vollständige Customer-Klasse
' Klassenmodul: Customer
Option Explicit
Private pNummer As Long
Private pName As String
Private pEmail As String
Private pErstellt As Date
' === PROPERTIES ===
Public Property Get Nummer() As Long
Nummer = pNummer
End Property
Public Property Let Nummer(ByVal value As Long)
If value > 0 Then
pNummer = value
Else
Err.Raise 5, , "Kundennummer muss > 0 sein"
End If
End Property
Public Property Get Name() As String
Name = pName
End Property
Public Property Let Name(ByVal value As String)
If Len(Trim(value)) > 0 Then
pName = Trim(value)
Else
Err.Raise 5, , "Name darf nicht leer sein"
End If
End Property
Public Property Get Email() As String
Email = pEmail
End Property
Public Property Let Email(ByVal value As String)
If InStr(value, "@") > 0 Then
pEmail = LCase(Trim(value))
Else
Err.Raise 5, , "Ungültige E-Mail-Adresse"
End If
End Property
Public Property Get Rabatt() As Double
' Geschäftslogik: Stammkunden bekommen mehr
If pNummer < 1000 Then
Rabatt = 0.05
ElseIf pNummer < 5000 Then
Rabatt = 0.1
Else
Rabatt = 0.15
End If
End Property
' === METHODEN ===
Public Function BerechneEndpreis(Bruttopreis As Double) As Double
BerechneEndpreis = Bruttopreis * (1 - Me.Rabatt)
End Function
Public Sub SendeEmail(Betreff As String, Text As String)
' Hier: Outlook-Integration
Debug.Print "E-Mail an " & pEmail & ": " & Betreff
End Sub
' === EVENTS ===
Private Sub Class_Initialize()
pErstellt = Now
pNummer = 0
pName = ""
pEmail = ""
End Sub
Private Sub Class_Terminate()
' Cleanup
End Sub
Verwendung:
Sub TestCustomerKlasse()
Dim kunde As New Customer
kunde.Nummer = 1234
kunde.Name = "PREDOC GmbH"
kunde.Email = "[email protected]"
Debug.Print "Rabatt: " & Format(kunde.Rabatt, "0%")
Debug.Print "1000€ kosten: " & kunde.BerechneEndpreis(1000) & "€"
kunde.SendeEmail "Angebot", "Vielen Dank..."
End Sub
Vorteile gegenüber prozeduralem Code
1. Wiederverwendbarkeit
Kopieren Sie das Klassenmodul in andere Projekte, dort ist es sofort einsatzbereit.
2. Wartbarkeit
Änderungen nur an einer Stelle (in der Klasse) statt in 50 Subs verstreut.
3. Datenkapselung
Private Variablen können nicht von außen verändert werden, dadurch ist Validierung erzwingbar.
4. Testbarkeit
Klassen können isoliert getestet werden.
5. Lesbarkeit
' Prozedural (unklar):
Call BerechneRabatt(kunde, betrag, datum)
' OOP (selbsterklärend):
kunde.BerechneEndpreis(betrag)
Bewährte Regeln für VBA-Klassen
- Option Explicit immer verwenden
- Private Variablen mit “p” oder “m_” prefixen
- Validierung in Properties einbauen (nicht blind schreiben)
- Read-Only Properties für berechnete Werte
- Fehlerbehandlung in Methoden (On Error GoTo)
- Kommentare für öffentliche Methoden
- Initialize für Standardwerte nutzen
- Terminate für Cleanup (Verbindungen schließen)
Wann OOP nutzen, wann nicht?
Nutzen Sie OOP wenn:
- Sie mehrere ähnliche Entitäten haben (Kunden, Produkte, Bestellungen)
- Komplexe Geschäftslogik strukturiert werden muss
- Code wiederverwendbar sein soll
- Mehrere Entwickler im Team arbeiten
Verzichten Sie auf OOP wenn:
- Es ein einfaches 20-Zeilen-Makro ist
- Einmalige Automatisierung ohne Wartung
- Performance kritisch ist (Klassen haben minimalen Overhead)
Fazit
Objektorientierte Programmierung macht aus VBA-Skripten professionelle Software:
- Klassen kapseln Daten und Logik
- Properties ermöglichen kontrollierte Zugriffe
- Methoden strukturieren Geschäftslogik
- Collections verwalten mehrere Objekte
- Events (Initialize/Terminate) für Setup/Cleanup
Investieren Sie Zeit in OOP, dann wird Ihr VBA-Code wartbarer, testbarer und professioneller.