yuliya ordner

main
Yuliya Rudenko 2024-05-30 15:29:03 +02:00
parent a8bc4525b3
commit 8364bf8671
23 changed files with 608 additions and 0 deletions

179
yuliya/aufgaben.md 100644
View File

@ -0,0 +1,179 @@
# Aufgabe 1
### Aufgabenstellung:
Erstellen Sie eine Klasse Person, die eine Instanzvariable name vom Typ String und
eine Instanzvariable age vom Typ int hat. Implementieren Sie einen entsprechenden
Kostruktor, der die Instanzvariablen initialisiert.
Fügen Sie außerdem eine Methode introduce() hinzu,
die eine Vorstellung der Person auf der Konsole ausgibt. Erstellen Sie eine Instanz
der Klasse und rufen Sie die Methode introduce() auf.
### Lösung
```
class Person {
String name
int age
Person(String name, int age) {
this.name = name
this.age = age
}
def introduce() {
println("Hello, my name is ${name} and I am ${age} years old.")
}
}
// Verwendung der Klasse Person
def person = new Person("Alice", 30)
person.introduce()
```
# Aufgabe 2
### Aufgabenstellung:
a) Erstelle eine Klasse Calculator, die Methoden für die Grundrechenoperationen
Addition, Subtraktion, Multiplikation und Division bereitstellt. Implementiere die
Methoden add(int a, int b), subtract(int a, int b), multiply(int a, int b) und
divide(int a, int b). Die Methoden sollen die beiden übergebenen Zahlen
entsprechend der Operation verarbeiten und das Ergebnis zurückgeben.
b) Erweitere die Klasse um eine Methode performOperation(int a, int b, Closure
operation), die eine Closure als Parameter akzeptiert. Diese Closure soll eine
Berechnung mit den beiden Zahlen durchführen und das Ergebnis zurückgeben. Zeige,
wie man diese Methode verwendet, indem du verschiedene Closures übergibst.
### Lösung
```
class Calculator {
def add(int a, int b) {
return a + b
}
def subtract(int a, int b) {
return a - b
}
def multiply(int a, int b) {
return a * b
}
def divide(int a, int b) {
if (b == 0) {
println("Error: Division by zero!")
return
}
return a / b
}
def performOperation(int a, int b, Closure operation) {
return operation(a, b)
}
}
// Verwendung der Klasse Calculator
def calc = new Calculator()
// Grundrechenoperationen
println("Addition: ${calc.add(5, 3)}")
println("Subtraction: ${calc.subtract(10, 7)}")
println("Multiplication: ${calc.multiply(4, 6)}")
println("Division: ${calc.divide(12, 4)}")
// Closures definieren
def addClosure = { int a, int b -> a + b }
def subtractClosure = { int a, int b -> a - b }
def multiplyClosure = { int a, int b -> a * b }
def divideClosure = { int a, int b ->
if (b == 0) {
println("Error: Division by zero!")
return
}
return a / b
}
// Verwendung von performOperation mit Closures
println("Addition mit Closure: ${calc.performOperation(5, 3, addClosure)}")
println("Subtraction mit Closure: ${calc.performOperation(10, 7, subtractClosure)}")
println("Multiplication mit Closure: ${calc.performOperation(4, 6, multiplyClosure)}")
println("Division mit Closure: ${calc.performOperation(12, 4, divideClosure)}")
```
# Aufgabe 3
### Aufgabenstellung
Erstellen Sie eine Klasse EmployeeManager, die die Verwaltung von Mitarbeitern
ermöglicht. Die Klasse soll folgende Funktionen bieten:
1. Hinzufügen von Mitarbeitern mit Name und Gehalt.
2. Aktualisieren des Gehalts eines Mitarbeiters.
3. Entfernen eines Mitarbeiters.
4. Durchführen von Gehaltsanpassungen für alle Mitarbeiter basierend auf einer Closure, die eine Gehaltsanpassungslogik definiert.
5. Abrufen einer Liste von Mitarbeitern, die nach einem bestimmten Kriterium gefiltert wurden (basierend auf einer übergebenen Closure).
```
class Employee {
String name
double salary
Employee(String name, double salary) {
this.name = name
this.salary = salary
}
String toString() {
return "Name: ${name}, Salary: ${salary}"
}
}
class EmployeeManager {
List<Employee> employees = []
void addEmployee(String name, double salary) {
employees << new Employee(name, salary)
}
void updateSalary(String name, double newSalary) {
employees.find { it.name == name }?.salary = newSalary
}
void removeEmployee(String name) {
employees.removeAll { it.name == name }
}
void adjustSalaries(Closure adjustmentLogic) {
employees.each { it.salary = adjustmentLogic(it.salary) }
}
List<Employee> filterEmployees(Closure criteria) {
return employees.findAll(criteria)
}
}
// Beispielnutzung der Klasse EmployeeManager
def manager = new EmployeeManager()
// Hinzufügen von Mitarbeitern
manager.addEmployee("Alice", 50000)
manager.addEmployee("Bob", 60000)
manager.addEmployee("Charlie", 55000)
// Aktualisieren des Gehalts eines Mitarbeiters
manager.updateSalary("Alice", 52000)
// Entfernen eines Mitarbeiters
manager.removeEmployee("Charlie")
// Durchführen von Gehaltsanpassungen für alle Mitarbeiter
manager.adjustSalaries { salary -> salary * 1.1 } // 10% Gehaltserhöhung
// Filtern von Mitarbeitern basierend auf einem Kriterium
def highEarners = manager.filterEmployees { it.salary > 55000 }
println("Alle Mitarbeiter:")
manager.employees.each { println it }
println("\nHigh Earners:")
highEarners.each { println it }
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

View File

@ -0,0 +1,429 @@
# Klassen
### Definition einer Klasse
Klassen in Groovy werden ähnlich wie in Java definiert, jedoch mit einigen
syntaktischen Erleichterungen: mit dem class-Schlüsselwort, ohne Semikolon
Beispiel
```
class Person {
String name
int age
}
```
### Konstruktoren
Groovy fügt automatisch einen Standardkonstruktor (="Default-Konstruktor") hinzu, wenn
keine Konstruktoren explizit definiert sind. Dieser Standardkonstruktor initialisiert alle
Eigenschaften der Klasse mit ihren Standardwerten.
Man kann auch benutzerdefinierte Konstruktoren definieren oder die beiden Konstruktorarten
auch gleichzeitig nutzen. Man spricht dabei von Konstruktorüberladung (auch wie in Java,
C++, C#...)
```
class Person {
String name
int age
//Default-Konstruktor
def person = new Person()
//benutzerdefinierter Konstruktor
Person(String name, int age) {
this.name = name
this.age = age
}
}
```
```
class Person {
String name
int age
Person() {
// Standardkonstruktor
}
Person(String name, int age) {
this.name = name
this.age = age
}
}
def person1 = new Person()
println(person1.name) // Ausgabe: null
println(person1.age) // Ausgabe: 0
def person2 = new Person("Alice", 30)
println(person2.name) // Ausgabe: Alice
println(person2.age) // Ausgabe: 30
```
### Standardkonstruktor mit Map
Groovy bietet eine spezielle Initialisierungsform mit einer Map an. Dieser Konstruktor
ermöglicht Objekte einfach und übersichtlich zu initialisieren, indem die Eigenschaften
des Objekts direkt in Form von Schlüssel-Wert-Paaren in der Map angegeben werden.
Groovy kümmert sich dann um die Zuordnung der Werte zu den entsprechenden Feldern der Klasse.
```
class Person {
String name
int age
// Map-Konstruktor
Person(Map properties) {
properties.each { key, value -> this."$key" = value }
}
}
Person person = new Person(name: 'John', age: 30)
println(person.name) // Ausgabe: John
println(person.age) // Ausgabe: 30
```
### Eigenschaften
Eigenschaften können direkt als Felder definiert werden. Groovy
generiert automatisch Getter- und Setter-Methoden (wie in Ruby)
Beispiel
```
Person person = new Person()
person.name = "John"
person.age = 30
println person.name
//John
```
Getter und Setter können aber auch manuell überschrieben werden
Beispiel
```
class Fruits {
private String fruitName
private String fruitColor
def setFruitName(String name) {
fruitName = name
}
def getFruitName() {
return "The fruitname is $fruitName"
}
def setFruitColor(String color) {
fruitColor = color
}
def getFruitColor(){
return "The color is $fruitColor"
}
static void(args) {
//Instanz erstellen
Fruits apple = new Fruits()
apple.setFruitName("apple")
apple.setFruitColor("red")
}
}
```
# Methoden
### Definition einer Methode
Methoden werden ähnlich wie in Java definiert, können aber optional einen Rückgabetyp
haben
```
class Calculator {
int add(int a, int b) {
return a + b
}
}
```
In Groovy können Methoden direkt ohne Klasse und main-Methode definiert und aufgerufen
werden.
Beispiel 1
```
def printHello() {
println "Hello..."
}
printHello()
def sum(int a, int b) {
println "Sum is "+(a+b)
}
sum(5,2)
//Hello...
// 7
```
### Instanzmethoden
Methoden können Instanzmethoden sein und auf Instanzvariablen zugreifen.
```
class Person {
String name
int age
// Instanzmethode, um die Person vorzustellen
def introduce() {
println("Hello, my name is ${name} and I am ${age} years old.")
}
}
Person person = new Person(name: 'Alice', age: 30)
person.introduce()
// Hello, my name is Alice and I am 30 years old.
```
### Statische Methoden
```
class MathUtils {
// Definition einer statischen Methode
static int add(int a, int b) {
return a + b
}
static void main(String[] args) {
// Aufruf der statischen Methode ohne Instanz der Klasse
int result = MathUtils.add(5, 10)
println("Sum is $result") // Ausgabe: Sum is 15
}
}
```
### Dynamische Methoden
Groovy erlaubt es, Methoden zur Laufzeit hinzuzufügen.
In diesem Beispiel wird die Methode sayHello zur Klasse DynamicExample hinzugefügt, nachdem
die Klasse bereits definiert wurde
Beispiel
Groovy ermöglicht es, Methoden zur Laufzeit hinzuzufügen, was eine hohe Flexibilität bei der Gestaltung
von Klassen und deren Verhalten bietet. Diese Fähigkeit ist Teil der dynamischen Natur von Groovy und
wird durch die metaClass-Eigenschaft ermöglicht
```
class DynamicExample {}
// Hinzufügen einer Methode(=closure) zur Laufzeit
DynamicExample.metaClass.sayHello = { -> println "Hello, World!" }
def example = new DynamicExample()
example.sayHello()
```
### Expando
Expando ist eine spezielle Klasse in Groovy, die ermöglicht, Objekten zur Laufzeit dynamisch Methoden und Eigenschaften
hinzuzufügen. Dadurch ist die vorherige Deklaration der Felder in der Klasse nicht nötig
Beispiel
```
// Erstellen eines Expando-Objekts
def expando = new Expando()
// Hinzufügen einer Eigenschaft 'name' und Zuweisung des Wertes "Groovy"
expando.name = "Groovy"
// Hinzufügen einer Methode 'sayHello', die eine Nachricht ausgibt, die die Eigenschaft 'name' verwendet
expando.sayHello = { -> println "Hello from $name" }
// Aufrufen der Methode 'sayHello', was die Nachricht "Hello from Groovy" ausgibt
expando.sayHello() // Ausgabe: Hello from Groovy
```
### Default-Parameter
Methodenparameter können Standdardwerte haben (wie in Ruby). Diese werden eingesetzt, falls beim Aufruf keine Parameter
gesetzt werden.
Beispiel 1
```
class Greeter {
void greet(String name = "World") {
println "Hello, $name!"
}
}
```
Ruft man die Methode ohne Parameter auf, werden die Default-Paramter eingesetzt
Beispiel 2
```
def sum(int a=10, int b=3) {
println "Sum is "+(a+b)
}
sum()
// Sum is 13
```
### Closures
Closures können auf Variablen aus ihrem umgebenden Gültigkeitsbereich zugreifen und diese
„einfangen“. Dadurch können sie auf Werte zugreifen, die zum Zeitpunkt ihrer Erstellung
existierten.
Closures enthalten Parameter, den Pfeil -> und den auszuführenden Code. Parameter sind
optional und werden, sofern angegeben, durch Kommas getrennt.
1. Parameter
```
//closure takes one parameter - name - and prints it when invoked
def greet = { String name -> println "Hello, $name!" }
greet.call("John")
```
2. Referenzierung von Variablen und Rückgabewerte
Dieses Beispiel zeigt, wie Closures auf Variablen im auf Variablen im umgebenden Kontext
zugreifen und diese beibehalten können. Somit wird es Closures ermöglicht, Zustände
zwischen verschiedenen Aufrufen beizubehalten.
```
def createCounter() {
def count = 0 //lokale var
return { ->
count += 1
return count
}
}
//Ergebnis bzw. closure wird counter zugewiesen
def counter = createCounter()
//counter hat zugriff auf count *innerhalb des Kontexts*
//in dem sie erstellt wurde
println(counter()) // Ausgabe: 1
println(counter()) // Ausgabe: 2
```
3. Übergabe als Parameter
```
def performOperation(int x, Closure operation) {
return operation(x)
}
def closure = { y -> y * 2 }
def result = performOperation(5, closure)
println(result) // Ausgabe: 10
```
### Wie ruft man eine Closure auf
Eine Closure kann sowohl als eine reguläre Methode als auch mit call aufrufen werden
```
// Closure-Definition
def greet = { name ->
return "Hello, ${name}!"
}
// Aufruf der Closure als reguläre Methode
println(greet("Alice")) // Ausgabe: Hello, Alice!
// Aufruf der Closure mit call
println(greet.call("Bob")) // Ausgabe: Hello, Bob!
```
Methoden können auch auf Maps und Listen angewendet werden, besonders nützlich mit Closures.
```
def myMap = [ 'subject': 'groovy', 'topic': 'closures']
println myMap.each { it }
def myList = [1, 2, 3, 4, 5]
println myList.find { item -> item == 3 } // 3
println myList.findAll { item -> item > 3 } // [4, 5]
println myList.any { item -> item > 5 } // false
println myList.every { item -> item > 3 } // false
println myList.collect { item -> item * 2 } // [2, 4, 6, 8, 10]
```
Im Gegensatz zu einer regulären Groovy-Methode:
- Wir können eine Closure als Argument an eine Methode übergeben
- Wir können eine Closure einer Variablen zuweisen und später ausführen, entweder als Methode oder mit call.
- Groovy bestimmt den Rückgabewert der Closures zur Laufzeit.
- Wir können Closures innerhalb einer Closure deklarieren und aufrufen.
- Closures geben immer einen Wert zurück
### Methodenverkettung
Methodenverkettung ermöglicht,dass Methodenaufrufe direkt nacheinander aufeinanderfolgen können, indem das Objekt
selbst (normalerweise mit this) zurückgegeben wird.
Dies ermöglicht eine flüssige und verständliche Art, Methoden aufzurufen und zu kombinieren, insbesondere wenn diese
Methoden denselben oder ähnlichen Kontext haben. (wie in JS, )
Beispiel
```
class FluentPerson {
String name
int age
FluentPerson setName(String name) {
this.name = name
return this
}
FluentPerson setAge(int age) {
this.age = age
return this
}
}
// Erstellen einer neuen FluentPerson-Instanz und Methodenverkettung
def person = new FluentPerson()
.setName("Alice")
.setAge(30)
println "Name: ${person.name}, Age: ${person.age}" // Ausgabe: Name: Alice, Age: 30
```
### Mixin(Misching)
Man kann Funktionalität zu Klassen hinzufügen, ohne Vererbung zu verwenden, indem man
Mixins verwendet.
Beispiel
```
class ExtraMethods {
String shout(String str) {
return str.toUpperCase()
}
}
@Mixin(ExtraMethods)
class MyClass {}
def myObject = new MyClass()
println myObject.shout("hello")
```

Binary file not shown.