OOP Begriffe: Attribute, Nachrichten, Methodenaufruf, Persistenz & Schnittstellen
Dieser Beitrag ist eine umfassende Erklärung der wichtigsten OOP-Begriffe – inklusive Attribute, Nachrichten, Methodenaufruf, Persistenz und Schnittstellen mit praktischen Beispielen.
In a Nutshell
OOP-Begriffe beschreiben die fundamentalen Konzepte objektorientierter Programmierung: Attribute als Eigenschaften, Nachrichten als Kommunikation, Persistenz als Datenhaltung und Schnittstellen als Verträge.
Kompakte Fachbeschreibung
Objektorientierte Programmierung (OOP) verwendet spezifische Begriffe zur Beschreibung von Konzepten und Strukturen.
Attribut (Attribute/Field/Property)
Ein Attribut ist eine Eigenschaft oder ein Zustand eines Objekts. Es beschreibt Daten, die ein Objekt enthält.
Eigenschaften:
- Datentyp: Definiert Art der Daten (String, int, boolean, etc.)
- Sichtbarkeit: public, private, protected, package
- Wert: Aktueller Zustand der Eigenschaft
- Lebensdauer: Existiert so lange wie das Objekt
Nachricht (Message/Methodenaufruf)
Eine Nachricht ist die Kommunikation zwischen Objekten. Sie fordert ein Objekt auf, eine bestimmte Aktion auszuführen.
Komponenten:
- Empfänger: Objekt, das die Nachricht erhält
- Selektor: Name der aufzurufenden Methode
- Argumente: Parameter für die Methode
- Rückgabewert: Ergebnis der Operation
Persistenz (Persistence)
Persistenz bezeichnet die Dauerhaftigkeit von Daten über die Programmlaufzeit hinaus.
Arten der Persistenz:
- Dateisystem: Serialisierung in Dateien
- Datenbanken: Relationale oder NoSQL-Datenbanken
- Cloud-Speicher: Externe Speicherdienste
- In-Memory: Temporäre Persistenz
Schnittstelle (Interface/API)
Eine Schnittstelle definiert einen Vertrag zwischen Komponenten und beschreibt, welche Operationen verfügbar sind.
Typen von Schnittstellen:
- Programmierschnittstellen: Methoden-Signaturen
- Web-APIs: HTTP-Endpunkte
- Benutzerschnittstellen: GUI-Komponenten
- Hardware-Schnittstellen: Gerätetreiber
Prüfungsrelevante Stichpunkte
- Attribute: Eigenschaften/Daten von Objekten mit Sichtbarkeit
- Nachrichten: Kommunikation zwischen Objekten via Methodenaufruf
- Methodenaufruf: Ausführung von Operationen auf Objekten
- Persistenz: Dauerhafte Datenspeicherung über Programmlaufzeit
- Schnittstellen: Verträge zwischen Komponenten, definierte APIs
- Kapselung: Daten und Methoden als Einheit
- Abstraktion: Komplexität reduzieren durch Vereinfachung
- IHK-relevant: Fundamentales Verständnis für OOP-Entwicklung
Kernkomponenten
- Attribute: Dateneigenschaften von Objekten
- Nachrichten: Objektkommunikation
- Methoden: Verhaltensimplementierung
- Persistenz: Datendauerhaftigkeit
- Schnittstellen: Definierte Verträge
- Kapselung: Daten- und Methodenbündelung
- Abstraktion: Komplexitätsreduktion
- Polymorphie: Mehrere Formen einer Schnittstelle
Praxisbeispiele
1. Attribute in verschiedenen Sprachen
// Java Attribute
public class Auto {
// Instanzattribute (pro Objekt)
private String marke; // Private Eigenschaft
protected int baujahr; // Geschützte Eigenschaft
public double preis; // Öffentliche Eigenschaft
// Klassenattribut (für alle Objekte gleich)
private static int anzahlAutos = 0;
// Konstante
public static final int MAX_GESCHWINDIGKEIT = 250;
// Konstruktor zur Initialisierung
public Auto(String marke, int baujahr, double preis) {
this.marke = marke;
this.baujahr = baujahr;
this.preis = preis;
Auto.anzahlAutos++; // Klassenattribut erhöhen
}
// Getter und Setter für gekapselte Attribute
public String getMarke() {
return marke;
}
public void setMarke(String marke) {
this.marke = marke;
}
public static int getAnzahlAutos() {
return anzahlAutos;
}
}
// C# Attribute
public class Mitarbeiter
{
// Auto-Properties (moderne Syntax)
public string Name { get; set; }
public int Alter { get; private set; } // Nur lesbar von außen
// Volle Property mit Validierung
private double gehalt;
public double Gehalt
{
get { return gehalt; }
set
{
if (value >= 0)
gehalt = value;
else
throw new ArgumentException("Gehalt kann nicht negativ sein");
}
}
// Statische Eigenschaft
public static string Firma { get; set; } = "TechCorp";
// Konstante
public const decimal MINDESTGEHALT = 2000m;
public Mitarbeiter(string name, int alter, double gehalt)
{
Name = name;
Alter = alter;
Gehalt = gehalt;
}
}
# Python Attribute
class Person:
# Klassenattribut
anzahl_personen = 0
def __init__(self, name, alter):
# Instanzattribute
self.name = name # Öffentlich
self._alter = alter # Geschützt (Konvention)
self.__geheim = "data" # Privat (Name Mangling)
Person.anzahl_personen += 1
# Property für gekapselten Zugriff
@property
def alter(self):
return self._alter
@alter.setter
def alter(self, wert):
if wert >= 0:
self._alter = wert
else:
raise ValueError("Alter kann nicht negativ sein")
# Statische Methode
@staticmethod
def get_anzahl_personen():
return Person.anzahl_personen
2. Nachrichten und Methodenaufrufe
// Nachrichten zwischen Objekten
public class Bankkonto {
private double kontostand;
private String kontonummer;
public Bankkonto(String kontonummer, double startbetrag) {
this.kontonummer = kontonummer;
this.kontostand = startbetrag;
}
// Methode zum Empfangen von Nachrichten
public void einzahlen(double betrag) {
if (betrag > 0) {
this.kontostand += betrag;
System.out.println("Einzahlung: " + betrag + "€, neuer Kontostand: " + kontostand + "€");
}
}
public boolean abheben(double betrag) {
if (betrag > 0 && kontostand >= betrag) {
kontostand -= betrag;
System.out.println("Abhebung: " + betrag + "€, neuer Kontostand: " + kontostand + "€");
return true;
}
return false;
}
public double getKontostand() {
return kontostand;
}
public String getKontonummer() {
return kontonummer;
}
}
// Kunde sendet Nachrichten an Bankkonto
public class Kunde {
private String name;
private Bankkonto konto;
public Kunde(String name, Bankkonto konto) {
this.name = name;
this.konto = konto;
}
// Kunde sendet Nachrichten an sein Konto
public void geldEinzahlen(double betrag) {
System.out.println(name + " will " + betrag + "€ einzahlen");
konto.einzahlen(betrag); // Nachricht senden
}
public boolean geldAbheben(double betrag) {
System.out.println(name + " will " + betrag + "€ abheben");
return konto.abheben(betrag); // Nachricht senden
}
public void kontostandPruefen() {
double stand = konto.getKontostand(); // Nachricht senden
System.out.println(name + "'s Kontostand: " + stand + "€");
}
}
// Verwendung der Nachrichten
public class BankingDemo {
public static void main(String[] args) {
Bankkonto konto = new Bankkonto("DE123456789", 1000.0);
Kunde kunde = new Kunde("Max Mustermann", konto);
// Nachrichtenkette
kunde.geldEinzahlen(500.0);
kunde.kontostandPruefen();
if (kunde.geldAbheben(200.0)) {
System.out.println("Abhebung erfolgreich");
}
kunde.kontostandPruefen();
}
}
3. Persistenz Implementierung
// Serialisierung für Datei-Persistenz
import java.io.*;
import java.util.*;
public class PersistenzDemo {
// Serialisierbare Klasse
static class Produkt implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String name;
private double preis;
private transient Date lastModified; // transient = nicht serialisiert
public Produkt(String id, String name, double preis) {
this.id = id;
this.name = name;
this.preis = preis;
this.lastModified = new Date();
}
// Getter und toString
public String getId() { return id; }
public String getName() { return name; }
public double getPreis() { return preis; }
@Override
public String toString() {
return String.format("Produkt[id=%s, name=%s, preis=%.2f]", id, name, preis);
}
}
// Persistenz-Manager
static class PersistenzManager {
private String dateiname;
public PersistenzManager(String dateiname) {
this.dateiname = dateiname;
}
// Objekte speichern
public void speichereProdukte(List<Produkt> produkte) throws IOException {
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream(dateiname))) {
oos.writeObject(produkte);
System.out.println("Produkte gespeichert in " + dateiname);
}
}
// Objekte laden
@SuppressWarnings("unchecked")
public List<Produkt> ladeProdukte() throws IOException, ClassNotFoundException {
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream(dateiname))) {
List<Produkt> produkte = (List<Produkt>) ois.readObject();
System.out.println("Produkte geladen aus " + dateiname);
return produkte;
}
}
}
// JSON-Persistenz (manuell)
static class JsonPersistenz {
public static void speichereAlsJson(List<Produkt> produkte, String dateiname) throws IOException {
try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(dateiname))) {
writer.write("[\n");
for (int i = 0; i < produkte.size(); i++) {
Produkt p = produkte.get(i);
writer.write(String.format(
" {\"id\": \"%s\", \"name\": \"%s\", \"preis\": %.2f}",
p.getId(), p.getName(), p.getPreis()
));
if (i < produkte.size() - 1) {
writer.write(",\n");
}
}
writer.write("\n]");
}
System.out.println("Produkte als JSON gespeichert");
}
}
public static void main(String[] args) {
List<Produkt> produkte = Arrays.asList(
new Produkt("P001", "Laptop", 999.99),
new Produkt("P002", "Maus", 29.99),
new Produkt("P003", "Tastatur", 79.99)
);
PersistenzManager manager = new PersistenzManager("produkte.ser");
try {
// Serialisierung
manager.speichereProdukte(produkte);
// Deserialisierung
List<Produkt> geladeneProdukte = manager.ladeProdukte();
geladeneProdukte.forEach(System.out::println);
// JSON-Persistenz
JsonPersistenz.speichereAlsJson(produkte, "produkte.json");
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
4. Schnittstellen und APIs
// Programmierschnittstelle (Interface)
interface DatenbankSchnittstelle {
// Abstrakte Methoden (ohne Implementierung)
void verbinden() throws DatenbankException;
void trennen();
boolean istVerbunden();
// Abfragemethoden
List<Map<String, Object>> abfragen(String sql) throws DatenbankException;
int ausfuehren(String sql) throws DatenbankException;
// Default-Methoden (seit Java 8)
default void verbindenMitTimeout(int timeout) throws DatenbankException {
verbinden(); // Standard-Implementierung
}
}
// Eigene Exception-Klasse
class DatenbankException extends Exception {
public DatenbankException(String nachricht) {
super(nachricht);
}
public DatenbankException(String nachricht, Throwable ursache) {
super(nachricht, ursache);
}
}
// Konkrete Implementierung
class MySQLDatenbank implements DatenbankSchnittstelle {
private boolean verbunden = false;
private String verbindungsString;
public MySQLDatenbank(String verbindungsString) {
this.verbindungsString = verbindungsString;
}
@Override
public void verbinden() throws DatenbankException {
try {
// Simulierte Verbindung
System.out.println("Verbinde zu MySQL: " + verbindungsString);
Thread.sleep(1000); // Simuliere Netzwerkverzögerung
verbunden = true;
System.out.println("Verbindung hergestellt");
} catch (InterruptedException e) {
throw new DatenbankException("Verbindung unterbrochen", e);
}
}
@Override
public void trennen() {
if (verbunden) {
System.out.println("Verbindung getrennt");
verbunden = false;
}
}
@Override
public boolean istVerbunden() {
return verbunden;
}
@Override
public List<Map<String, Object>> abfragen(String sql) throws DatenbankException {
if (!verbunden) {
throw new DatenbankException("Nicht verbunden");
}
System.out.println("Führe aus: " + sql);
// Simuliertes Ergebnis
List<Map<String, Object>> ergebnis = new ArrayList<>();
Map<String, Object> zeile = new HashMap<>();
zeile.put("id", 1);
zeile.put("name", "Testdaten");
ergebnis.add(zeile);
return ergebnis;
}
@Override
public int ausfuehren(String sql) throws DatenbankException {
if (!verbunden) {
throw new DatenbankException("Nicht verbunden");
}
System.out.println("Führe aus: " + sql);
return 1; // Simulierte betroffene Zeilen
}
}
// API-Verwendung
public class ApiDemo {
public static void main(String[] args) {
// Polymorphe Verwendung über Interface
DatenbankSchnittstelle db = new MySQLDatenbank("jdbc:mysql://localhost/test");
try {
// Über die Schnittstelle arbeiten
db.verbinden();
if (db.istVerbunden()) {
List<Map<String, Object>> ergebnis = db.abfragen("SELECT * FROM kunden");
System.out.println("Ergebnis: " + ergebnis.size() + " Zeilen");
int rows = db.ausfuehren("UPDATE kunden SET status = 'active'");
System.out.println("Betroffene Zeilen: " + rows);
}
} catch (DatenbankException e) {
System.err.println("Datenbankfehler: " + e.getMessage());
} finally {
db.trennen();
}
}
}
5. Web-API Beispiel
// REST API Controller (Spring Boot Beispiel)
@RestController
@RequestMapping("/api/kunden")
public class KundenAPI {
private final KundenService service;
public KundenAPI(KundenService service) {
this.service = service;
}
// GET /api/kunden/{id}
@GetMapping("/{id}")
public ResponseEntity<Kunde> getKunde(@PathVariable Long id) {
try {
Kunde kunde = service.findeKundeById(id);
return ResponseEntity.ok(kunde);
} catch (KundeNotFoundException e) {
return ResponseEntity.notFound().build();
}
}
// POST /api/kunden
@PostMapping
public ResponseEntity<Kunde> createKunde(@RequestBody Kunde kunde) {
Kunde erstellterKunde = service.erstelleKunde(kunde);
return ResponseEntity.status(HttpStatus.CREATED).body(erstellterKunde);
}
// PUT /api/kunden/{id}
@PutMapping("/{id}")
public ResponseEntity<Kunde> updateKunde(@PathVariable Long id, @RequestBody Kunde kunde) {
try {
Kunde aktualisierterKunde = service.aktualisiereKunde(id, kunde);
return ResponseEntity.ok(aktualisierterKunde);
} catch (KundeNotFoundException e) {
return ResponseEntity.notFound().build();
}
}
// DELETE /api/kunden/{id}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteKunde(@PathVariable Long id) {
service.loescheKunde(id);
return ResponseEntity.noContent().build();
}
}
// Datenmodell
class Kunde {
private Long id;
private String name;
private String email;
private LocalDate geburtsdatum;
// Getter und Setter
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public LocalDate getGeburtsdatum() { return geburtsdatum; }
public void setGeburtsdatum(LocalDate geburtsdatum) { this.geburtsdatum = geburtsdatum; }
}
OOP-Konzepte im Überblick
Kapselung
// Daten und Methoden werden zu einer Einheit gekapselt
public class Bankkonto {
private double kontostand; // Private Daten
public void einzahlen(double betrag) { // Öffentliche Methode
if (betrag > 0) {
kontostand += betrag;
}
}
public double getKontostand() {
return kontostand;
}
}
Abstraktion
// Komplexe Realität wird vereinfacht
abstract class Fahrzeug {
protected String marke;
public abstract void beschleunigen();
public abstract void bremsen();
public void anzeigen() {
System.out.println("Fahrzeug: " + marke);
}
}
Polymorphie
// Eine Schnittstelle, viele Implementierungen
interface Tier {
void macheLaut();
}
class Hund implements Tier {
public void macheLaut() {
System.out.println("Wuff!");
}
}
class Katze implements Tier {
public void macheLaut() {
System.out.println("Miau!");
}
}
// Verwendung
Tier tier1 = new Hund();
Tier tier2 = new Katze();
tier1.macheLaut(); // Wuff!
tier2.macheLaut(); // Miau!
Persistenz-Strategien
Serialisierung
- Java Serialization:
SerializableInterface - JSON: Menschlich lesbar, plattformunabhängig
- XML: Strukturiert, mit Metadaten
- Binary: Kompakt, schnell
Datenbank-Persistenz
- Relationale DB: Strukturierte Daten mit SQL
- NoSQL DB: Flexible Dokumente oder Key-Value
- ORM: Object-Relational Mapping
- JPA/Hibernate: Java Persistence API
Cloud-Persistenz
- Object Storage: S3, Azure Blob Storage
- Databases-as-a-Service: Firebase, Supabase
- Caching: Redis, Memcached
API-Typen
Programmierschnittstellen
- Local APIs: Methoden in gleichen Programm
- Library APIs: Fremde Bibliotheken
- Framework APIs: Spring, Django, React
Web-APIs
- REST: HTTP-Methoden, Statuscodes
- GraphQL: Flexible Abfragesprache
- gRPC: Hochperformante RPC
- WebSocket: Echtzeitkommunikation
Plattform-APIs
- OS APIs: Windows, Linux, macOS
- Mobile APIs: Android, iOS
- Cloud APIs: AWS, Azure, GCP
Vorteile und Nachteile
Vorteile von OOP-Begriffen
- Strukturierung: Klare Organisation von Code
- Wiederverwendbarkeit: Komponenten können wiederverwendet werden
- Wartbarkeit: Modularer Aufbau erleichtert Änderungen
- Testbarkeit: Isolierte Komponenten sind leicht testbar
- Skalierbarkeit: Systeme können wachsen
Nachteile
- Komplexität: Overhead bei kleinen Projekten
- Lernkurve: Viele Konzepte zu verstehen
- Performance: Manchmal langsamer als prozeduraler Code
- Over-Engineering: Gefahr der Überkomplexität
Häufige Prüfungsfragen
-
Was ist der Unterschied zwischen Attribut und Methode? Attribute sind Eigenschaften/Daten, Methoden sind Verhalten/Funktionen eines Objekts.
-
Erklären Sie den Begriff Nachricht in der OOP! Nachricht ist die Kommunikation zwischen Objekten, meist als Methodenaufruf implementiert.
-
Was bedeutet Persistenz in der Programmierung? Daten dauerhaft speichern, sodass sie über Programmlaufzeiten hinweg verfügbar bleiben.
-
Wozu dienen Schnittstellen (Interfaces)? Definieren Verträge zwischen Komponenten und ermöglichen lose Kopplung und Polymorphie.
Wichtigste Quellen
- https://de.wikipedia.org/wiki/Objektorientierte_Programmierung
- https://docs.oracle.com/javase/tutorial/java/concepts/
- https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/