482 lines
18 KiB
Org Mode
482 lines
18 KiB
Org Mode
Programmentwurf
|
||
|
||
[Bezeichung]
|
||
|
||
Name: [Name, Vorname]\\
|
||
Martrikelnummer: [MNR]
|
||
|
||
Abgabedatum: [DATUM]
|
||
|
||
*
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: section
|
||
:END:
|
||
Allgemeine Anmerkungen:
|
||
|
||
- es darf nicht auf andere Kapitel als Leistungsnachweis verwiesen
|
||
werden (z.B. in der Form “XY wurde schon in Kapitel 2 behandelt, daher
|
||
hier keine Ausführung”)
|
||
|
||
- alles muss in UTF-8 codiert sein (Text und Code)
|
||
|
||
- sollten mündliche Aussagen den schriftlichen Aufgaben widersprechen,
|
||
gelten die schriftlichen Aufgaben (ggf. an Anpassung der schriftlichen
|
||
Aufgaben erinnern!)
|
||
|
||
- alles muss ins Repository (Code, Ausarbeitung und alles was damit
|
||
zusammenhängt)
|
||
|
||
- die Beispiele sollten wenn möglich vom aktuellen Stand genommen werden
|
||
|
||
- finden sich dort keine entsprechenden Beispiele, dürfen auch ältere
|
||
Commits unter Verweis auf den Commit verwendet werden
|
||
- Ausnahme: beim Kapitel “Refactoring” darf von vorne herein aus allen
|
||
Ständen frei gewählt werden (mit Verweis auf den entsprechenden
|
||
Commit)
|
||
|
||
- falls verlangte Negativ-Beispiele nicht vorhanden sind, müssen
|
||
entsprechend mehr Positiv-Beispiele gebracht werden
|
||
|
||
- Achtung: werden im Code entsprechende Negativ-Beispiele gefunden,
|
||
gibt es keine Punkte für die zusätzlichen Positiv-Beispiele
|
||
|
||
- Beispiele
|
||
|
||
- “Nennen Sie jeweils eine Klasse, die das SRP einhält bzw.
|
||
verletzt.”
|
||
|
||
- Antwort: Es gibt keine Klasse, die SRP verletzt, daher hier 2
|
||
Klassen, die SRP einhalten: [Klasse 1], [Klasse 2]
|
||
- Bewertung: falls im Code tatsächlich keine Klasse das SRP
|
||
verletzt: volle Punktzahl ODER falls im Code mind. eine Klasse
|
||
SRP verletzt: halbe Punktzahl
|
||
|
||
- verlangte Positiv-Beispiele müssen gebracht werden
|
||
|
||
- Code-Beispiel = Code in das Dokument kopieren
|
||
|
||
* Kapitel 1: *Einführung*
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: kapitel-1-einführung
|
||
:END:
|
||
*** Übersicht über die Applikation
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: übersicht-über-die-applikation
|
||
:END:
|
||
[Was macht die Applikation? Wie funktioniert sie? Welches Problem löst
|
||
sie/welchen Zweck hat sie?]
|
||
|
||
Die Anwendung ist zur organisierten Abspeicherung von Links bzw. URLs gedacht.
|
||
Diese können durch die Anwendung abgespeichert werden.
|
||
Zur besseren Organisation ist es außerdem möglich, Kategorien anzulegen und die Links diesen zuzuordnen, wie beispielsweise 'Libary', 'Selfhostable', 'Dienst' usw.
|
||
Zusätzlich kann die Anwendung auch Tags zu Links hinzufügen können, wenn die Implementation Webseite beispielsweise bereits kennt (z.B. 'Github').
|
||
Eigene Regeln für Tags können auch angelegt werden, sie werden durch einen Regulären Ausdruck beschrieben.
|
||
Der User, welcher einen Eintrag angelegt hat wird auch gespeichert.
|
||
|
||
TODO: Die Anwendung soll Persistenz enthalten sowie verschiedene Methoden zum Durchsuchen (nach Kategorie, User) und Exportieren der Daten.
|
||
|
||
*** Wie startet man die Applikation?
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: wie-startet-man-die-applikation
|
||
:END:
|
||
[Wie startet man die Applikation? Welche Voraussetzungen werden
|
||
benötigt? Schritt-für-Schritt-Anleitung]
|
||
**** Voraussetzungen:
|
||
- Java 17
|
||
- Maven
|
||
|
||
**** Compilieren
|
||
#+begin_src shell
|
||
mvn clean install
|
||
#+end_src
|
||
|
||
**** Ausführen
|
||
#+begin_src
|
||
java -jar 0-Plugin/target/0-Plugin-1.0-SNAPSHOT-jar-with-dependencies.jar [PARAMETER]
|
||
#+end_src
|
||
|
||
*** Wie testet man die Applikation?
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: wie-testet-man-die-applikation
|
||
:END:
|
||
[Wie testet man die Applikation? Welche Voraussetzungen werden benötigt?
|
||
Schritt-für-Schritt-Anleitung]
|
||
|
||
#+begin_src
|
||
mvn clean test
|
||
#+end_src
|
||
* Kapitel 2: Clean Architecture
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: kapitel-2-clean-architecture
|
||
:END:
|
||
*** Was ist Clean Architecture?
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: was-ist-clean-architecture
|
||
:END:
|
||
[allgemeine Beschreibung der Clean Architecture in eigenen Worten]
|
||
|
||
Die Clean Architecture ist eine Software Architektur, die es ermöglichen soll langlebige Systeme zu entwickeln.
|
||
Dazu wird der eigentliche Zweck einer Anwendung von möglichst vielen technischen Details getrennt.
|
||
Auf diese Weise soll ein Kern der Anwendung entstehen, welcher beispielsweise die Businessregeln enthält und bis auf die Wahl der Programmiersprache (für Langlebigkeit von Sprachen siehe bspw. Java) keine Abhängigkeiten zu technischen Entscheidungen hat.
|
||
Konkretere technische Details, wie beispielsweise die Wahl einer Datenbank oder ob für die Benutzerschnittstelle ein CLI oder ein Webserver genutzt wird, werden an den Rand der Anwendung gedrängt und nur durch Zwischenschichten mit dem Kern verbunden.
|
||
|
||
Die konkreten Schichten sind (von langlebig nach kurzlebig und von wenigen (keinen) nach vielen Abhängigkeiten sortiert):
|
||
- Abstraction Code
|
||
- Domain Code
|
||
- Application Code
|
||
- Adapters
|
||
- Plugins
|
||
|
||
Durch die Dependency Rule wird sichergestellt, dass Abhängigkeiten immer von außen nach innen sind, und somit eine äußere Schicht ausgetauscht werden könnte, ohne, dass die inneren Schichten angepasst werden müssten.
|
||
|
||
*** Analyse der Dependency Rule
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: analyse-der-dependency-rule
|
||
:END:
|
||
[(1 Klasse, die die Dependency Rule einhält und eine Klasse, die die
|
||
Dependency Rule verletzt); jeweils UML der Klasse und Analyse der
|
||
Abhängigkeiten in beide Richtungen (d.h., von wem hängt die Klasse ab
|
||
und wer hängt von der Klasse ab) in Bezug auf die Dependency Rule]
|
||
|
||
|
||
Da die Abhängigkeiten zwischen den einzelnen Schichten durch Maven restriktiv kontrolliert werden gibt es kein negativ Beispiel.
|
||
|
||
**** Positiv-Beispiel: Dependency Rule
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: positiv-beispiel-dependency-rule
|
||
:END:
|
||
|
||
[[./uml/LinkCliAdapter.png]]
|
||
|
||
[[./uml/LinkCliAdapterClasses.png]]
|
||
|
||
Die Klasse LinkCliAdapter ist selbst abhängig von einigen Value Object der Domäne (LinkUrl, UserName, CategoryName) und dem LinkUseCase sowie seinem speziellen Format LinkDto aus der Application Schicht.
|
||
Abhängig von der Klasse LinkCliAdapter ist die Klasse LinkCommands aus der Plugin Schicht.
|
||
**** 2. Positiv-Beispiel: Dependency Rule
|
||
|
||
[[./uml/CSVCategoryPersistenceAdapter.png]]
|
||
[[./uml/CSVCategoryPersistenceAdapterClasses.png]]
|
||
|
||
Die Klasse CSVCategoryPersistenceAdapter ist abhängig von dem Domänen Entity Category und Implementiert das Interface der Domäne PersistenceAdapter<Category>. Außerdem ist es abhängig vom Persitenz Entity CategorEntity, das in der Adapter Schicht definiert ist und dem Interface GenericDAO<CategorEntity> aus der Adapter Schicht.
|
||
In der Plugin Schicht ist mit dem GenericCSVDAO<T> eine Klasse gegeben, die dieses Interface implementiert.
|
||
|
||
Das Domänen Repository CategoryRepository ist abhängig von einem PersistenceAdapter (Interface), welche das CSVCategoryPersistenceAdapter implementiert.
|
||
Somit ist das Repository der Domäne zur Compile Zeit nicht abhängig von dem CSVCategoryPersistenceAdapter des Adapter sondern nur zur Runtime, da im Adapter eine Implementation des benötigten Interfaces liegt.
|
||
*** *Analyse der Schichten*
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: analyse-der-schichten
|
||
:END:
|
||
[jeweils 1 Klasse zu 2 unterschiedlichen Schichten der
|
||
Clean-Architecture: jeweils UML der Klasse (ggf. auch zusammenspielenden
|
||
Klassen), Beschreibung der Aufgabe, Einordnung mit Begründung in die
|
||
Clean-Architecture]
|
||
|
||
**** Schicht: Domain
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: schicht-name
|
||
:END:
|
||
|
||
[[./uml/LinkUrl.png]]
|
||
|
||
Die Klasse LinkUrl ist ein Klasse, welche einen zentralen Bestandteil der zu speichernden Daten repräsentiert: Die URL eines Links.
|
||
Damit ist sie Teil der Domäne, da es sich direkt um die Businessregeln der zu verarbeiten Daten handelt.
|
||
So stellt sie beispielsweise durch die Verwendung der Java Klasse URL sicher, dass die Url ein valides Format hat und somit die Domänenregeln erfüllt.
|
||
|
||
**** Schicht: Plugin
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: schicht-name-1
|
||
:END:
|
||
|
||
[[./uml/GitHubTagMatcher.png]]
|
||
|
||
Die Klasse GitHubTagMatcher ist eine Implementation der des Interface TagMatcher und dafür verantwortlich festzustellen, ob ein Link auf eine GitHub Url verweist und im positiv Fall zu versuchen über die GitHub Repository-Api zusätzliche Informationen über das verlinkte Repository zu erhalten.
|
||
Die Klasse ist Teil der Plugin Schicht, da die Interaktion mit der GitHub Repository-Rest-Api eindeutig eine Abhängigkeiten zu einem fremden Bestandteil darstellt und solche Abhängigkeiten an den Rand der Anwendung gedrängt werden sollten.
|
||
|
||
* Kapitel 3: SOLID
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: kapitel-3-solid
|
||
:END:
|
||
*** Analyse Single-Responsibility-Principle (*SRP)*
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: analyse-single-responsibility-principle-srp
|
||
:END:
|
||
[jeweils eine Klasse als positives und negatives Beispiel für SRP;
|
||
jeweils UML der Klasse und Beschreibung der Aufgabe bzw. der Aufgaben
|
||
und möglicher Lösungsweg des Negativ-Beispiels (inkl. UML)]
|
||
|
||
**** Positiv-Beispiel
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: positiv-beispiel
|
||
:END:
|
||
**** Negativ-Beispiel
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: negativ-beispiel
|
||
:END:
|
||
|
||
*** Analyse Open-Closed-Principle (OCP)
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: analyse-open-closed-principle-ocp
|
||
:END:
|
||
[jeweils eine Klasse als positives und negatives Beispiel für OCP;
|
||
jeweils UML der Klasse und Analyse mit Begründung, warum das OCP
|
||
erfüllt/nicht erfüllt wurde -- falls erfüllt: warum hier
|
||
sinnvoll/welches Problem gab es? Falls nicht erfüllt: wie könnte man es
|
||
lösen (inkl. UML)?]
|
||
|
||
**** Positiv-Beispiel
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: positiv-beispiel-1
|
||
:END:
|
||
**** Negativ-Beispiel
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: negativ-beispiel-1
|
||
:END:
|
||
|
||
*** Analyse Liskov-Substitution- (LSP), Interface-Segreggation- (ISP), Dependency-Inversion-Principle (DIP)
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: analyse-liskov-substitution--lsp-interface-segreggation--isp-dependency-inversion-principle-dip
|
||
:END:
|
||
[jeweils eine Klasse als positives und negatives Beispiel für entweder
|
||
LSP oder ISP oder DIP); jeweils UML der Klasse und Begründung, warum man
|
||
hier das Prinzip erfüllt/nicht erfüllt wird]
|
||
|
||
[Anm.: es darf nur ein Prinzip ausgewählt werden; es darf NICHT z.B. ein
|
||
positives Beispiel für LSP und ein negatives Beispiel für ISP genommen
|
||
werden]
|
||
|
||
**** Positiv-Beispiel
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: positiv-beispiel-2
|
||
:END:
|
||
**** Negativ-Beispiel
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: negativ-beispiel-2
|
||
:END:
|
||
|
||
* Kapitel 4: Weitere Prinzipien
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: kapitel-4-weitere-prinzipien
|
||
:END:
|
||
*** Analyse GRASP: Geringe Kopplung
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: analyse-grasp-geringe-kopplung
|
||
:END:
|
||
[jeweils eine bis jetzt noch nicht behandelte Klasse als positives und
|
||
negatives Beispiel geringer Kopplung; jeweils UML Diagramm mit
|
||
zusammenspielenden Klassen, Aufgabenbeschreibung und Begründung für die
|
||
Umsetzung der geringen Kopplung bzw. Beschreibung, wie die Kopplung
|
||
aufgelöst werden kann]
|
||
|
||
**** Positiv-Beispiel
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: positiv-beispiel-3
|
||
:END:
|
||
**** Negativ-Beispiel
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: negativ-beispiel-3
|
||
:END:
|
||
|
||
*** Analyse GRASP: Hohe *Kohäsion*
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: analyse-grasp-hohe-kohäsion
|
||
:END:
|
||
[eine Klasse als positives Beispiel hoher Kohäsion; UML Diagramm und
|
||
Begründung, warum die Kohäsion hoch ist]
|
||
|
||
*** *Don't Repeat Yourself (DRY)*
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: dont-repeat-yourself-dry
|
||
:END:
|
||
[ein Commit angeben, bei dem duplizierter Code/duplizierte Logik
|
||
aufgelöst wurde; Code-Beispiele (vorher/nachher); begründen und
|
||
Auswirkung beschreiben]
|
||
|
||
*
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: section-1
|
||
:END:
|
||
* Kapitel 5: *Unit Tests*
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: kapitel-5-unit-tests
|
||
:END:
|
||
*** 10 Unit Tests
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: unit-tests
|
||
:END:
|
||
[Nennung von 10 Unit-Tests und Beschreibung, was getestet wird]
|
||
|
||
| Unit Test | Beschreibung |
|
||
| Klasse#Methode | |
|
||
| | |
|
||
| | |
|
||
| | |
|
||
| | |
|
||
| | |
|
||
| | |
|
||
| | |
|
||
| | |
|
||
| | |
|
||
|
||
*** ATRIP: Automatic
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: atrip-automatic
|
||
:END:
|
||
[Begründung/Erläuterung, wie ‘Automatic' realisiert wurde]
|
||
|
||
*** ATRIP: Thorough
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: atrip-thorough
|
||
:END:
|
||
[jeweils 1 positives und negatives Beispiel zu ‘Thorough'; jeweils
|
||
Code-Beispiel, Analyse und Begründung, was professionell/nicht
|
||
professionell ist]
|
||
|
||
*** ATRIP: Professional
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: atrip-professional
|
||
:END:
|
||
[jeweils 1 positives und negatives Beispiel zu ‘Professional'; jeweils
|
||
Code-Beispiel, Analyse und Begründung, was professionell/nicht
|
||
professionell ist]
|
||
|
||
*** Code Coverage
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: code-coverage
|
||
:END:
|
||
[Code Coverage im Projekt analysieren und begründen]
|
||
|
||
*** Fakes und Mocks
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: fakes-und-mocks
|
||
:END:
|
||
[Analyse und Begründung des Einsatzes von 2 Fake/Mock-Objekten;
|
||
zusätzlich jeweils UML Diagramm der Klasse]
|
||
|
||
* Kapitel 6: Domain Driven Design
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: kapitel-6-domain-driven-design
|
||
:END:
|
||
*** Ubiquitous Language
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: ubiquitous-language
|
||
:END:
|
||
[4 Beispiele für die Ubiquitous Language; jeweils Bezeichung, Bedeutung
|
||
und kurze Begründung, warum es zur Ubiquitous Language gehört]
|
||
|
||
| Bezeichung | Bedeutung | Begründung |
|
||
| Link | Steht für eine eindeutige URL, die von der Anwendung gespeichert werden soll | Gehört zur Ubiquitous-Laguage, weil Link außerhalb der Domäne der Anwendung auch anders verwendet werden kann |
|
||
| Category | Steht für eine Kategorie, die einem Link zugeordnet werden kann | Gehört zur Ubiquitous-Laguage, weil nur im Kontext der Anwendung klar ist, wofür die Kategorien verwendet werden |
|
||
| Tag | Steht für einen Tag der automatisch bestimmten Link-Typen zugeordnet wird | Gehört zur Ubiquitous-Laguage, weil nur im Kontext der Anwendung klar ist, was genau getaggt wird und wie dies geschieht |
|
||
| *TagMatcher | Steht für eine spezielle Implementation des Interfaces TagMatcher (z.B. GitHubTagMatcher), das dafür sorgt, dass einem Link ein Tag zugewiesen werden kann | Gehört zur Ubiquitous-Laguage, weil nur im Kontext der Anwendung klar ist, auf welche Tag sich die Funktion bezieht und was deren Bedeutung ist. |
|
||
|
||
*** Entities
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: entities
|
||
:END:
|
||
[UML, Beschreibung und Begründung des Einsatzes einer Entity; falls
|
||
keine Entity vorhanden: ausführliche Begründung, warum es keines geben
|
||
kann/hier nicht sinnvoll ist]
|
||
|
||
*** Value Objects
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: value-objects
|
||
:END:
|
||
/[UML, Beschreibung und Begründung des Einsatzes eines Value Objects;
|
||
falls kein Value Object vorhanden: ausführliche Begründung, warum es
|
||
keines geben kann/hier nicht sinnvoll ist]/
|
||
|
||
Klasse: Category Name
|
||
|
||
*** Repositories
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: repositories
|
||
:END:
|
||
[UML, Beschreibung und Begründung des Einsatzes eines Repositories;
|
||
falls kein Repository vorhanden: ausführliche Begründung, warum es
|
||
keines geben kann/hier nicht sinnvoll ist]
|
||
|
||
*** Aggregates
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: aggregates
|
||
:END:
|
||
[UML, Beschreibung und Begründung des Einsatzes eines Aggregates; falls
|
||
kein Aggregate vorhanden: ausführliche Begründung, warum es keines geben
|
||
kann/hier nicht sinnvoll ist]
|
||
|
||
* Kapitel 7: Refactoring
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: kapitel-7-refactoring
|
||
:END:
|
||
*** Code Smells
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: code-smells
|
||
:END:
|
||
/[jeweils 1 Code-Beispiel zu 2 Code Smells aus der Vorlesung; jeweils
|
||
Code-Beispiel und einen möglichen Lösungsweg bzw. den genommen
|
||
Lösungsweg beschreiben (inkl./ /(Pseudo-)Code)]/
|
||
**** Duplicated Code
|
||
Da es bei Java keine Funktion zum durchsuchen eines Sets gibt wurde an mehreren Stellen ein Konstrukt, wie unten sichtbar
|
||
verwendet.
|
||
Dies macht den Code unleserlich und schwerer zu warten.
|
||
#+begin_src java
|
||
// LinkRepository.java
|
||
public Optional<Link> getById(LinkId id) {
|
||
return links.stream().filter(link -> link.getId().equals(id)).findFirst();
|
||
}
|
||
|
||
public Optional<Link> getByUrl(LinkUrl url) {
|
||
return links.stream().filter(link -> link.getUrl().equals(url)).findFirst();
|
||
}
|
||
#+end_src
|
||
|
||
Durch die Einführung des Dekorator-Entwurfsmuster für Set wurde jedoch auch eine eigene Implementation eines Sets eingeführt.
|
||
Dadurch konnte diese Set Implementation auch einfach durch eine find Methode ergänzt werden, wie dargestellt.
|
||
|
||
#+begin_src java
|
||
// CustomStrictSet.java
|
||
@Override
|
||
public Optional<T> find(Predicate<T> predicate) {
|
||
return set.stream().filter(predicate).findFirst();
|
||
}
|
||
#+end_src
|
||
|
||
So wurde die Codezeile an vier Stellen ersetzt.
|
||
Wenn das Refactoring nicht recht früh durchgeführt worden wäre, wären es eventuell sogar mehr Stellen
|
||
geworden.
|
||
|
||
#+begin_src java
|
||
// LinkRepository.java
|
||
public Optional<Link> getById(LinkId id) {
|
||
return links.find(link -> link.getId().equals(id));
|
||
}
|
||
|
||
public Optional<Link> getByUrl(LinkUrl url) {
|
||
return links.find(link -> link.getUrl().equals(url));
|
||
}
|
||
#+end_src
|
||
|
||
Das Refactoring wurde mit Commit [[https://tea.filefighter.de/qvalentin/LinkDitch/commit/e4f167074250e791f293eb834a60eb9f63a34664][e4f1670742]] durchgeführt.
|
||
*** 2 Refactorings
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: refactorings
|
||
:END:
|
||
[2 unterschiedliche Refactorings aus der Vorlesung anwenden, begründen,
|
||
sowie UML vorher/nachher liefern; jeweils auf die Commits verweisen]
|
||
|
||
* Kapitel 8: Entwurfsmuster
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: kapitel-8-entwurfsmuster
|
||
:END:
|
||
/[2 unterschiedliche Entwurfsmuster aus der Vorlesung (oder nach
|
||
Absprache auch andere) jeweils sinnvoll einsetzen, begründen und
|
||
UML-Diagramm]/
|
||
|
||
*** Entwurfsmuster: [Name]
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: entwurfsmuster-name
|
||
:END:
|
||
*** Entwurfsmuster: [Name]
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: entwurfsmuster-name-1
|
||
:END:
|