Kapselung, Vererbung und Polymorphismus in C#
Lernen Sie Kapselung, Vererbung und Polymorphismus in C# mit Beispielen, um zentrale OOP-Konzepte sicher anzuwenden.
Objektorientierte Programmierung (OOP) ist ein Ansatz, der entwickelt wurde, um wiederverwendbaren, wartbaren und verständlichen Code zu schreiben. Die drei Grundpfeiler der OOP sind:
- Encapsulation (Kapselung) → Daten verbergen und kontrollierten Zugriff ermöglichen
- Inheritance (Vererbung) → Gemeinsames Verhalten an Unterklassen weitergeben
- Polymorphism (Polymorphismus) → Dieselbe Methode verhält sich in unterschiedlichen Objekten unterschiedlich
Werden diese drei Eigenschaften zusammen verwendet, kann in Softwareprojekten eine solide Architektur aufgebaut werden. Schauen wir uns nun jede einzeln an.
Encapsulation (Kapselung)
Kapselung verbirgt die interne Struktur einer Klasse vor der Außenwelt und macht nur das Notwendige zugänglich.
Dadurch wird eine direkte Manipulation der Daten verhindert, Fehler werden reduziert und Änderungen an der internen Logik wirken sich nicht auf die Außenwelt aus.
In C# wird dies mit Zugriffsmodifikatoren wie private, protected, internal, public umgesetzt.
In der Regel werden Felder verborgen und über Properties oder Methoden kontrollierter Zugriff bereitgestellt.
public class BankAccount
{
private decimal _balance; // direkter Zugriff verboten
public decimal Balance
{
get => _balance;
private set => _balance = value;
}
public void Deposit(decimal amount)
{
if (amount <= 0)
throw new ArgumentException("Der Betrag muss größer als null sein.");
Balance += amount;
}
public void Withdraw(decimal amount)
{
if (amount > Balance)
throw new InvalidOperationException("Unzureichendes Guthaben.");
Balance -= amount;
}
}
In diesem Beispiel kann der Kontostand (_balance) nicht direkt verändert werden.
Der Benutzer kann nur über die Methoden Deposit und Withdraw darauf zugreifen.
Dadurch wird eine fehlerhafte Nutzung verhindert und Datensicherheit gewährleistet.
Inheritance (Vererbung)
Vererbung ermöglicht es einer Klasse, Eigenschaften und Verhalten von einer anderen Klasse zu erben. Dadurch wird gemeinsamer Code zentralisiert und wiederverwendbar. Die Basisklasse definiert allgemeines Verhalten, während die abgeleiteten Klassen spezialisierte Funktionen hinzufügen.
public class Animal
{
public string Name { get; set; } = string.Empty;
public void Eat()
{
Console.WriteLine($"{Name} frisst.");
}
}
public class Dog : Animal
{
public void Bark()
{
Console.WriteLine($"{Name} bellt.");
}
}
public class Cat : Animal
{
public void Meow()
{
Console.WriteLine($"{Name} miaut.");
}
}
class Program
{
static void Main()
{
Dog d = new Dog { Name = "Bello" };
d.Eat(); // von Animal geerbt
d.Bark(); // spezifisch für Dog
Cat c = new Cat { Name = "Minka" };
c.Eat(); // von Animal geerbt
c.Meow(); // spezifisch für Cat
}
}
Hier erben sowohl Dog als auch Cat von Animal.
Das gemeinsame Verhalten Eat() wird nur einmal geschrieben und ist in allen Unterklassen verfügbar.
Polymorphism (Polymorphismus)
Polymorphismus bedeutet, dass dieselbe Methode je nach Objekt unterschiedlich funktioniert. Es gibt zwei Arten von Polymorphismus:
- Compile-time Polymorphism: Erreicht durch Methodenüberladung (method overloading).
- Runtime Polymorphism: Erreicht durch
virtualundoverride.
public class Animal
{
public string Name { get; set; } = string.Empty;
public virtual void Speak()
{
Console.WriteLine($"{Name} macht ein Geräusch.");
}
}
public class Dog : Animal
{
public override void Speak()
{
Console.WriteLine($"{Name} bellt.");
}
}
public class Cat : Animal
{
public override void Speak()
{
Console.WriteLine($"{Name} miaut.");
}
}
class Program
{
static void Main()
{
Animal a1 = new Dog { Name = "Bello" };
Animal a2 = new Cat { Name = "Minka" };
a1.Speak(); // Bello bellt.
a2.Speak(); // Minka miaut.
}
}
Derselbe Speak()-Aufruf erzeugt je nach Objekttyp unterschiedliche Ausgaben.
Diese Flexibilität ist eine der stärksten Eigenschaften der OOP.
Beispiel: Buchtypen
Lassen Sie uns Bücher in einer Bibliotheksanwendung modellieren.
Gemeinsame Eigenschaften werden in der Book-Klasse definiert, während jede Unterklasse eigene Informationen hinzufügt oder
die Methode PrintInfo() überschreibt.
Außerdem werden Author- und Publisher-Klassen verwendet, um Autoren- und Verlagsinformationen separat zu speichern.
Dies zeigt, wie Vererbung und Polymorphismus zusammen eingesetzt werden können.
public class Author
{
public string Name { get; set; } = string.Empty;
public string Country { get; set; } = string.Empty;
}
public class Publisher
{
public string Name { get; set; } = string.Empty;
public string Address { get; set; } = string.Empty;
}
public abstract class Book
{
public string Title { get; set; } = string.Empty;
public Author BookAuthor { get; set; } = new Author();
public Publisher BookPublisher { get; set; } = new Publisher();
public int Pages { get; set; }
public string ISBN { get; set; } = string.Empty;
public int Year { get; set; }
// Soll in Unterklassen überschrieben werden
public abstract void PrintInfo();
}
public class ScienceBook : Book
{
public string Field { get; set; } = string.Empty; // Physik, Chemie, Biologie
public override void PrintInfo()
{
Console.WriteLine($"[Wissenschaftsbuch] {Title} - {BookAuthor.Name}, {Pages} Seiten");
Console.WriteLine($"Fachgebiet: {Field}, ISBN: {ISBN}, Verlag: {BookPublisher.Name}");
}
}
public class HistoryBook : Book
{
public string Period { get; set; } = string.Empty; // Antike, Mittelalter usw.
public override void PrintInfo()
{
Console.WriteLine($"[Geschichtsbuch] {Title} - {BookAuthor.Name}, {Pages} Seiten");
Console.WriteLine($"Epoche: {Period}, ISBN: {ISBN}, Verlag: {BookPublisher.Name}");
}
}
class Program
{
static void Main()
{
var publisher = new Publisher { Name = "Wissensverlag", Address = "Berlin" };
var author1 = new Author { Name = "Albert Einstein", Country = "Deutschland" };
var author2 = new Author { Name = "Halil Inalcik", Country = "Türkei" };
Book b1 = new ScienceBook
{
Title = "Relativitätstheorie",
BookAuthor = author1,
BookPublisher = publisher,
Pages = 250,
ISBN = "123-456-789",
Year = 1920,
Field = "Physik"
};
Book b2 = new HistoryBook
{
Title = "Das Osmanische Reich",
BookAuthor = author2,
BookPublisher = publisher,
Pages = 500,
ISBN = "987-654-321",
Year = 1973,
Period = "Osmanische Epoche"
};
b1.PrintInfo();
Console.WriteLine();
b2.PrintInfo();
}
}
Vorteile
- Encapsulation: Gewährleistet Datensicherheit, verhindert fehlerhafte Nutzung.
- Inheritance: Verringert Code-Duplikate, schafft eine hierarchische Struktur.
- Polymorphism: Ermöglicht eine flexible und erweiterbare Architektur.
TL;DR
- Encapsulation: Verbirgt interne Daten und ermöglicht kontrollierten Zugriff.
- Inheritance: Eigenschaften und Verhalten der Basisklasse werden an Unterklassen weitergegeben.
- Polymorphism: Dieselbe Methode kann sich in verschiedenen Unterklassen unterschiedlich verhalten.
Ähnliche Artikel
Dependency Injection Grundlagen in C#
Lernen Sie die Grundlagen von Dependency Injection in C#, um Abhängigkeiten zu verwalten und lose Kopplung zu erreichen.
Interfaces und Abstrakte Klassen in C#
Lernen Sie Interfaces und abstrakte Klassen in C#, ihre Unterschiede und den Einsatz für sauberes, erweiterbares Design.
Klassen, Objekte, Eigenschaften und Methoden in C#
Erlernen Sie die Grundlagen von Klassen, Objekten, Eigenschaften und Methoden in C# für objektorientierte Programmierung.
Konstruktoren, Destruktoren und this in C#
Lernen Sie Konstruktoren, Destruktoren und das Schlüsselwort this in C# zur Verwaltung des Objektlebenszyklus.
Record Types und Unveränderliche Objekte in C#
Lernen Sie Record Types und unveränderliche Objekte in C# kennen, inklusive Value Equality, with-Expressions und Best Practices.
SOLID-Prinzipien mit C#
SOLID-Prinzipien mit C#-Beispielen: flexiblen, wartbaren und testbaren Code erstellen.
Structs in C# – Unterschiede zu Klassen
Erfahren Sie die Unterschiede zwischen Structs und Klassen in C# in Bezug auf Speicher, Vererbung und Performance.