Einführung in OOP: Warum prozedurale Programmierung endet
Zuletzt aktualisiert:
5 Min. Lesezeit

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, die auch Microsofts Referenz zur objektorientierten Programmierung in C# anhand von Klassen, Structs und Records erklärt. 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. Die Werkzeuge dafür sehen wir uns im Beitrag zu Zugriffsmodifizierern einzeln an.
2. Vererbung
Codewiederholung vermeiden. Die Klassen SavingsAccount und CheckingAccount können gemeinsame Eigenschaften von BankAccount erben. Wie das mit virtual, override und base aufgebaut wird, erkläre ich im Leitfaden zu Vererbung und Polymorphie.
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. C# bietet dafür zwei Werkzeuge; wann Sie welches wählen, vergleiche ich in Interface vs. abstrakte Klasse.
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#; die gesamte Sprache können Sie in Microsofts offiziellem C#-Leitfaden nachschlagen. 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. Wenn Sie diese Grundlagen lieber mit einer Lehrkraft erarbeiten möchten, fasst der Beitrag worauf es bei der Wahl eines .NET-Experten als Lehrer ankommt die Auswahlkriterien zusammen.
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.
Häufig gestellte Fragen
Muss ich prozedurale Programmierung beherrschen, bevor ich OOP lerne?
Ja, die Grundlagen brauchen Sie: Variablen, Schleifen, Bedingungen und Methoden. OOP ersetzt sie nicht, sondern zeigt Ihnen, wie Sie sie in Klassen organisieren.
Muss in C# alles innerhalb einer Klasse stehen?
Oberflächlich nein: Dank Top-Level-Statements können Sie Code direkt in Program.cs schreiben, und der Compiler verpackt ihn im Hintergrund in eine Klasse. Sobald Sie eigene Typen definieren, verwenden Sie class, struct oder record.
Warum beginnen wir mit class, wenn es struct und record gibt?
Eine class ist ein Referenztyp, unterstützt Vererbung und ist das einzige Konstrukt, an dem sich alle vier OOP-Prinzipien zeigen lassen. struct eignet sich für kleine Werttypen, record für unveränderliche Datenträger; beides lernt sich deutlich leichter, sobald das Klassen-Denken sitzt.
Verwandte Artikel
C# Zugriffsmodifizierer: Türen abschließen oder offen lassen?
Was bedeuten public, private, protected und internal? Wie Getter- und Setter-Methoden Daten sichern, am Beispiel eines Bankkontos.
C# Konstruktor: der heimliche Held der Objekterzeugung
Was ist ein Konstruktor und warum brauchen wir ihn? Standardkonstruktor, parametrisierter Konstruktor und Konstruktor-Überladung an Beispielen aus der Praxis.
C# Klasse und Objekt: Bauplan und Produkt
Die Grundbausteine der OOP – Klasse und Objekt – anhand der Analogie einer Backform lernen und Property, Methode und Instanz an Beispielen aus der Praxis üben.