Einführung in OOP: Warum prozedurale Programmierung an Grenzen stößt
Einführung in OOP: Mit meinem Code stimmte etwas nicht
Vor Jahren war mein erster Kontakt mit dem Programmieren einfach: Code von oben nach unten schreiben, Zeile für Zeile. Variablen deklarieren, Funktionen schreiben, aufrufen, Ergebnis erhalten. Das wirkte übersichtlich – bis die Projekte größer wurden.
Eines Tages fand ich mich in einer einzigen Datei mit 2000 Zeilen wieder. „Welche Funktion ruft welche auf?“, „Wer hat diese Variable verändert?“ – während ich mit diesen Fragen kämpfte, wurde mir klar: Hier stimmte etwas grundsätzlich nicht.
Prozedurale Programmierung: guter Start, aber …
Prozedurale Programmierung ist eigentlich ein logischer Ansatz. Stellen Sie sich ein Rezept vor:
// Procedural approach - Simple calculator
double balance = 1000;
void Deposit(double amount)
{
balance += amount;
Console.WriteLine($"Deposited: ${amount}, New balance: ${balance}");
}
void Withdraw(double amount)
{
if (balance >= amount)
{
balance -= amount;
Console.WriteLine($"Withdrawn: ${amount}, New balance: ${balance}");
}
else
{
Console.WriteLine("Insufficient balance!");
}
}
// Usage
Deposit(500);
Withdraw(200);Schön, es funktioniert. Aber was, wenn wir mehrere Konten hätten? Und wenn jedes Konto andere Eigenschaften hätte? Kreditkonten, Sparkonten, Fremdwährungskonten …
Genau hier beginnt der prozedurale Ansatz zu bröckeln.
Spaghetticode: der Albtraum aller Entwickler
Das größte Problem prozeduralen Codes: Alles hängt mit allem zusammen. Sie ändern eine Sache, und etwas anderes geht kaputt. Wir nennen das „Spaghetticode“. Können Sie bei einem Teller Spaghetti sagen, welche Nudel wohin führt? Genau so wird der Code.
// Spaghetti code example - Real-life code to avoid
string account1_owner = "John";
double account1_balance = 1000;
string account1_type = "checking";
string account2_owner = "Jane";
double account2_balance = 5000;
string account2_type = "savings";
string account3_owner = "Bob";
double account3_balance = 2500;
string account3_type = "foreign";
// Money transfer? Which one to which? Which variable to use?
// Add new account? account4, account5, account6...
// What about 100 accounts? 🤯Je größer dieser Code wird, desto unbeherrschbarer wird er. Jede neue Funktion erhöht die Komplexität exponentiell.
In der echten Welt läuft es anders
Halten wir kurz inne. In der echten Welt gibt es Objekte:
- Auto: Hat Farbe, Geschwindigkeit, Marke. Kann gestartet und angehalten werden.
- Bankkonto: Hat Inhaber und Saldo. Man kann Geld einzahlen und abheben.
- Telefon: Hat Modell und Akkustand. Kann telefonieren und Nachrichten senden.
Diese Objekte haben Eigenschaften und Verhalten (Methoden). Und das Beste: Sie sind voneinander unabhängig!
Ein Auto zu starten wirkt sich nicht auf ein anderes Auto aus. Eine Nachricht von einem Telefon zu senden leert nicht den Akku eines anderen.
Genau das leistet OOP: Sie überträgt Objekte der echten Welt in Code.
OOP: die echte Welt in den Code holen
Schreiben wir dasselbe Bankkonto-Beispiel mit objektorientierter Programmierung (OOP):
public class BankAccount
{
// Properties
public string AccountOwner { get; set; }
public double Balance { get; private set; }
public string AccountType { get; set; }
// Constructor - Called when object is created
public BankAccount(string owner, double initialBalance, string type)
{
AccountOwner = owner;
Balance = initialBalance;
AccountType = type;
}
// Behaviors (Methods)
public void Deposit(double amount)
{
Balance += amount;
Console.WriteLine($"${amount} deposited to {AccountOwner}'s account.");
}
public bool Withdraw(double amount)
{
if (Balance >= amount)
{
Balance -= amount;
Console.WriteLine($"${amount} withdrawn from {AccountOwner}'s account.");
return true;
}
Console.WriteLine("Insufficient balance!");
return false;
}
public void ShowBalance()
{
Console.WriteLine($"{AccountOwner} - {AccountType}: ${Balance}");
}
}Wenn wir nun 100 Konten anlegen möchten:
// Each account carries its own data and behavior
BankAccount johnAccount = new BankAccount("John", 1000, "Checking");
BankAccount janeAccount = new BankAccount("Jane", 5000, "Savings");
BankAccount bobAccount = new BankAccount("Bob", 2500, "Foreign");
johnAccount.Deposit(500);
janeAccount.Withdraw(1000);
bobAccount.ShowBalance();
// Operations on John's account don't affect Jane's!Wie sauber ist das denn? Jedes Konto lebt in seinem eigenen Universum und beeinflusst die anderen nicht.
Die vier Säulen der OOP
Bei OOP geht es nicht nur darum, Klassen zu schreiben. Dahinter stehen vier Grundprinzipien. Wir behandeln sie in den kommenden Beiträgen ausführlich, hier eine kurze Vorstellung:
1. Kapselung
Daten schützen. Die Variable Balance kann nicht direkt von außen verändert werden, sondern nur über die Methoden Deposit und Withdraw.
2. Vererbung
Codewiederholung vermeiden. Die Klassen SavingsAccount und CheckingAccount können gemeinsame Eigenschaften von BankAccount erben.
3. Polymorphie
Dieselbe Methode zeigt unterschiedliches Verhalten. Die Methode Withdraw kann bei einem Sparkonto Zinsgebühren abziehen, bei einem Girokonto dagegen nicht.
4. Abstraktion
Komplexität verbergen. Die Nutzerin ruft einfach Deposit() auf, ohne von Datenbankzugriffen, Protokollierung oder Benachrichtigungen im Hintergrund wissen zu müssen.
Welche Sprachen unterstützen OOP?
OOP ist nicht an eine Sprache gebunden. Viele moderne Sprachen unterstützen sie:
| Sprache | OOP-Unterstützung | Anmerkungen |
|---|---|---|
| C# | ✅ Vollständig | Die OOP-orientierte Sprache von Microsoft |
| Java | ✅ Vollständig | Philosophie „Alles ist ein Objekt“ |
| Python | ✅ Vollständig | Dynamische und flexible OOP |
| Dart | ✅ Vollständig | Die Sprache von Flutter |
| Swift | ✅ Vollständig | Apple-Ökosystem |
| JavaScript | ⚠️ Prototypbasiert | Klassen-Syntax kam mit ES6 hinzu |
| C | ❌ Keine | Prozedurale Sprache |
In dieser Blogreihe verwenden wir C#. Warum?
- Klare und gut lesbare Syntax
- Vollständige OOP-Unterstützung
- Hervorragende IDE-Unterstützung (Visual Studio, Rider)
- Weit verbreitet in echten Projekten
Wann sollten Sie OOP einsetzen?
OOP ist kein Allheilmittel. Für kleine Skripte und einfache Automatisierungen kann prozedurales Vorgehen genügen. Aber:
✅ OOP verwenden:
- Wenn das Projekt wachsen wird
- Wenn mehrere Entwickler daran arbeiten
- Wenn Wartbarkeit und Erweiterbarkeit zählen
- Wenn Sie Objekte der echten Welt modellieren
❌ Prozedural genügt:
- Einmalige Skripte
- Kleine Automatisierungsaufgaben
- Performancekritische hardwarenahe Abläufe
Nächster Schritt: Klasse und Objekt
In diesem Beitrag haben wir gelernt, warum es OOP gibt, wo der prozedurale Ansatz an Grenzen stößt und welche vier Grundprinzipien dahinterstehen.
Im nächsten Beitrag tauchen wir tief in die Konzepte Klasse und Objekt ein. Mit der Analogie „Backform und Kuchen“ machen wir sie greifbar.
Halten Sie Ihren Code sauber und Ihren Kopf frei! 🚀
Dies ist der erste Beitrag der Reihe „OOP mit C#“. Im weiteren Verlauf behandeln wir Klassen, Konstruktoren, Zugriffsmodifizierer und viele weitere Themen.