Objektorientierung und Paradigmen
Value Objects
Value Objects sind Objekte, die nur einen Wert darstellen und keine Identität haben. Zwei Value Objects sind gleich, wenn sie die gleichen Eigenschaften haben.
Sie besitzen keine Identität und sind unveränderlich. Nach dem Erstellen kann nichts mehr geändert werden und Änderungen erzeugen immer ein neues Value Object.
Was sind Records?
Records können wie Klassen Felder, Properties und Methoden haben.
Definiert werden Records mit record
public record class Point {
public int X { get; init; }
public int Y { get; init; }
}init bedeutet, dass die Eigenschaften nur im Konstruktor gesetzt werden können.
Unterschied zwischen class und record:
-
classprüft auf Referenzgleichheit. Zeigen Variablen A und B auf denselben Speicherplatz?- Sind zwei
PersonObjekte gleich, wenn Sie den selben Namen haben?
- Sind zwei
-
recordprüft auf Wertgleichheit. Haben zwei Variablen den gleichen Inhalt?- Zwei
PersonRecords mit dem selben Namen sind gleich
- Zwei
Die Besonderheit von Records ist, dass sie automatisch die Equals und GetHashCode Methoden implementieren und auf strukturelle Gleichheit prüft anstatt auf Referenzgleichheit.
Records sind immutable und können nur durch Kopien geändert werden.
Um Änderungen zu ermöglichen, kann man die with Syntax verwenden.
var point = new Point { X = 1, Y = 2 };
var point2 = point with { X = 3 };Was bewirkt sealed?
sealed bewirkt, dass die Klasse nicht mehr von anderen Klassen erweitert werden kann.
Andere Klassen können nicht von einer sealed Klasse erben.
Diese Syntax bietet einen Schutz vor Manipulation.
public sealed class MyClass {
// ...
}Was ist ein Programmierparadigma?
Ein Programmierparadigma ist ein grundlegendes Konzept, das die Art und Weise beschreibt, wie ein Programm entworfen und strukturiert wird um ein Problem zu lösen.
Was sind die Merkmale eines Programmierparadigmas?
- Bestimmte Prinzipien und Regeln: Jedes Paradigma definiert grundlegende Prinzipien und Regeln für die Organisation von Code.
- Unterschiedliche Sichtweisen auf Probleme: Paradigmen prägen die Perspektive aus der Probleme betrachtet und gelöst werden.
- Bestimmte Techniken und Konstrukte: Ein Paradigma bestimmt, welche Techniken und Sprachkonstrukte bevorzugt werden.
Welche Programmparadigment gibt es
Prozedural Programmierung
Der Code wird in Form von Funktionen und Prozeduren organisiert die nacheinander ausgeführt werden. Dieses Paradigma findet man vor allem in alten Programmiersprachen wie C oder Fortran.
Ein Programm besteht aus einer hierarchischen Struktur von Unterprogrammaufrufen. Variablen können global für das gesamte Programm oder lokal für eine einzelne Routine gelten.
Man unterscheidet zwischen der funktionalen Routine und der prozeduralen Routine.
Funktionale Routine: Das Unterprogramm liefert einen Rückgabewert. Prozedurale Routine: Das Unterprogramm liefert keinen Rückgabewert.
Es gibt auch die strukturierte Programmierung, die eine Kombination aus imperativ und prozedural ist. Durch den Einsatz von drei grundlegenden Kontrollstrukturen lässt sich jeder Programmfluss ausdrücken ohne auf unkontrollierte Sprünge zurückzugreifen.
- Sequenz: Die Abarbeitung von Anweisungen in der Reihenfolge, in der sie stehen.
- Selektion: Die Auswahl zwischen verschiedenen Programmabläufen basierend auf einer Bedingung.
- Iteration: Die wiederholte Ausführung von Anweisungen basierend auf einer Bedingung.
Merkmale: Globale Variablen, statische Methoden, Schritt-für-Schritt
Objektorientiert Programmierung (Prüfung)
Ein Programm als eine Sammlung von Objekten die sowohl Daten (Attribute) als auch Verhalten (Methoden) besitzen. Da die Inhalte von Variablen in Objekten nach der Ausführung von Methoden erhalten bleiben, kann auf globale Variablen verzichtet werden.
Jedes Objekt ist einzigartig. Zwei Objekte können die gleichen Daten haben, werden aber im Speicher an unterschiedlichen Adressen gespeichert.
Gängige Sprachen die OOP unterstützen sind C#, Java, Python, Ruby, JavaScript, PHP, etc.
Merkmale: Objekte, Klassen, Vererbung
public class BankKonto // Klasse (Bauplan)
{
private decimal _saldo; // Gekapselter Zustand
public void Einzahlen(decimal betrag) // Verhalten
{
if (betrag < 0) throw new ArgumentException(); // Validierung
_saldo += betrag; // Zustandsänderung (Mutation)
}
}Funktionale Programmierung (Prüfung)
Bei der funktionalen Programmierung werden Funktionen verwendet und Zustandsänderungen vermieden.
Variablen sind unveränderbar und können nur durch eine Kopie geändert werden.
Man möchte gerne Laufvariablen (i++ in for-Schleifen) vermeiden, weshalb man Rekursionen statt Schleifen verwendet.
Außerdem werden Funktionen als Daten behandelt. Das bedeutet, dass Funktionen als Parameter oder Rückgabewerte verwendet werden können.
var zahlen = new List<int> { 1, 2, 3, 4, 5 };
var summe = zahlen.Select(zahl => zahl * 2).Sum(); // Ein neues Array wird erstelltDeklarative Programmierung (Prüfung)
Deklarative Programmierung ist ein Überbegriff unter dem auch funktionale Aspekte fallenm. Der Fokus liegt hierbei auf dem Ergebnis und nicht auf dem Weg dorthin.
Klassische Kontrollstrukturen wie if-else und for-Schleifen weerden nicht verwendet, sonder das System entscheidet wie es das Ergebnis erzielt. Man selbst beschreibt nur den Soll-Zustand.
Oft wird dies in SQL Queries oder HTML verwendet
var ergebnis = from k in kunden
where k.Alter > 18
select k.Name;
// Imperativ
List<Kunde> ergebnis = new List<Kunde>();
foreach (var k in kunden) {
if (k.Alter > 18) {
ergebnis.Add(k);
}
}Logische Programmierung
Ein Programm wird nicht als Abfolge von Befehlen, sondern als eine Menge von Logikregeln beschrieben. Der Computer nutzt diese Regeln um durch logisches Schlussfolgern eigenständig Lösungen zu ermitteln.
Protokollorientierte Programmierung
Protokolle beschreiben, welches Verhalten ein Typ bereitstellen soll, ohne dabei die konkrete Implementierung festzulegen.
Aspektorientierte Programmierung
Es zielt darauf ab, sogenannte Cross-Cutting Concerns modular und übersichtlich zu behandeln. Solche Belange, etwas Logging, Fehlerbehandlung, Sicherheitsüberprüfung, Transaktionsmanagment betreffen oft viele unterschiedliche Teile eines Programms und würden ohne AOP zu verstreutem, schwer wartbarem Code führen.
Ein Advice beschreibt wie das Verhalten einer Anwendung an bestimmten Stellen ergänzt werden soll.
Ein Join Point ist ein definierter Punkt im Programmablauf an dem zusätzlicher Code eingefügt werden kann. Typische Join Points sind Methodenaufrufe, Ausnahmen oder Attributzugriffe.
Ein Pointcut definiert eine Menge von Join Points, an denen ein bestimmter Aspekt wirksam werden soll.
Unterschied zwischen Imperativ und Deklarativ?
Jedes Paradigma lässt sich in zwei Hauptgruppen unterteilen:
Imperativ: (“Befehlshaber”) Dem Computer wird beschrieben WIE er etwas tun soll (Schritt-für-Schritt) Deklarativ: (“Kunde”) Man sagt dem Computer WAS man haben möchte (“Ich möchte … haben”)
Kombination aus Paradigmen?
Viele Sprachen sind Multi-Paradigmen. Objektorientierte Sprachen sind oft Imperativ, da sie innerhalb der Methoden Schritt-für-Schritt beschrieben werden. Objektorientiert kann auch verbunden werden mit Deklarativ, wenn Abfragen deklarativ sind (Beispiel: SQL Queries).
Probleme bei Objektorientierung?
Cross-Cutting Concerns wie Logging oder Security lassen sich nicht sauber in einer Klasse kapseln. Sie verteilen sich über den ganzen Code (Code Scattering) und vermischen sich mit der Fachlogik (Code Tangling).
Es gibt neben Vorteilen auch Nachteile bei der Objektorientierung:
**Tight Coupling (Zu starke Kopplung): **
Wenn eine Klasse stark auf andere Klassen angewiesen ist, kann es zu Problemen kommen, wenn sich eine der abhängigen Klassen ändert.
God Object (Große Klassen):
Eine Klasse macht “alles”. Dadurch wird die Klasse groß, untestbar und schwer zu warten.
Was ist Cross-Cutting Concerns?
Übergreifende Themen die mehrere Fachgebiete oder Bereiche betreffen und daher nicht eindeutig einem einzelnen Bereich zugeordnet werden können. Darunter fallen Themen wie Logging, Transaktionen, Security, etc.
Definition: Funktionalität die an vielen verschiedenen Stellen im Programm benötigt werden und sich nicht sauber in eine einzelne Fachklasse trennen lassen.
Was ist Code Scattering?
Wenn es Cross-Cutting Concerns gibt, dann kommt es automatisch zu Code Scattering.
Jede Klasse und Methode die Logging benötigt, muss den gleichen Logging Code implementieren. Der gleiche Code ist damit an sehr vielen Stellen im Programm verstreut. Möchte man die Art des Loggings ändern, muss man den Code an vielen Stellen im Programm ändern.
Was ist Code Tangling?
Das ist ein Problem, wenn eine Klasse mehrere Aufgaben übernimmt die sie gar nicht machen soll.
Eine Methode die eigentlich nur Geld überweisen soll, übernimmt nun auch das Logging, die Sicherheit und Fehlerbehandlung. Der eigentliche Code für die Überweisung ist mit Infrastrukturscode vermischt.
Kontrolle der API. Warum?
- Bibliothek abschotten?
- API solide nach außen
- Implementierung nach außen nicht sichtbar
public, private, internal
public: Die Methode, Variable oder Klasse ist im gesamten Projekt sichtbar.
private:
Die Methode, Variable oder Klasse ist nur innerhalb der Klasse sichtbar.
protected: Die Methode, Variable oder Klasse ist nur in der Klasse und in abgeleiteten Klassen sichtbar.
internal: Nur innerhalb der selben Assembly (Projekt) sichtbar.
72. Klassenaufbau
73. Wie beschreibe ich eine Methode
Wie beschreibt man Eigenschaften?
Eigenschaften sind Attribute mit Getter und Setter. Man kapselt Feldzugriffe via get (Lesen) und set (Schreiben).
public class MyClass {
private int _age; // Field
public int Age {
get { return _age; }
set { _age = value; }
}
public string Name { get; set; }
}Indizierte Eigenschaften
Indizierte Eigenschaften sind Eigenschaften, die wie ein Array angesprochen werden können. Sie haben einen Indexer, der wie ein Array angesprochen werden kann.
public class MyClass {
private int[] _numbers = new int[10];
public int this[int index] {
get { return _numbers[index]; }
}
private readonly Person[] _persons = [];
public Person this[int index] {
get { return _persons[index]; }
set { _persons[index] = value; }
}
}Konstruktoren
Der Konstruktor initialisiert ein Objekt und setzt Startwerte für die Eigenschaften.
public class MyClass {
private int _age;
public MyClass(int age) {
_age = age;
}
}Finalizer
Finalizer sind Methoden, die aufgerufen werden, wenn ein Objekt aus dem Speicher entfernt wird. Sie werden nur aufgerufen, wenn der Garbage Collector das Objekt freigibt.
public class MyClass {
~MyClass() {
// ...
}
}Interfaces
Interfaces sind Verträge die nur eine Signatur (Methodenköpfe, Properties, Events) besitzen und keine Implementierung.
Sie definieren was ein Objekt kann und nicht wie es es kann.
Interfaces beginnen immer mit einem I (ICollection, IEnumerable, IDisposable, etc.)
Eine Klasse die ein Interface implementiert, muss alle Methoden und Properties des Interfaces implementieren.
Der Vorteil von Interfaces ist, dass eine Klasse mehrere Interfaces implementieren kann.
// Interface definieren
public interface IMyInterface {
void DoSomething();
int MyProperty { get; set; }
}
// Klasse implementiert Interface
public class MyClass : IMyInterface {
public void DoSomething() {
// ...
}
public int MyProperty { get; set; }
}- Von A-Z kennen
Collections
Vorraussetzung: Damit eine Klasse als Collection genutzt werden kann, muss sie IEnumerable<T> implementieren und eine Methode GetEnumerator() bereitstellen.
public class MyClass : IEnumerable<T> {
private readonly List<T> _items = [];
internal void Add(T item) {
_items.Add(item);
}
public int Count => _items.Count;
public T this[int index] => _items[index];
public IEnumerator<T> GetEnumerator() {
return _items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
}Was ist Boxing und Unboxing?
Boxing ist die Umwandlung von einem Werttyp in ein Objekttyp. Dadurch wird ein Wert auf den Heap kopiert. Unboxing wandelt ein Objekttyp wieder in einen Werttyp um.
Der Nachteil dieses Vorgangs ist, dass beides zeitaufwendige Operationen sind und Performance kosten. Vermieden kann das durch die Verwendung von Generics.
// Boxing
int i = 10;
object o = i;
// Unboxing
int i = (int)o;