TU Wien:Objektorientierte Programmiertechniken VU (Puntigam)/Wiederholungsfragen 2019W

Aus VoWi
Zur Navigation springen Zur Suche springen

Folgende Fragen sollen beim Erarbeiten des Stoffes helfen. Sie stellen keine vollständige Aufzählung möglicher Prüfungsfragen dar.

Paradigmen der Programmierung[Bearbeiten | Quelltext bearbeiten]

1. Was versteht man unter einem Programmierparadigma?[Bearbeiten | Quelltext bearbeiten]

Eine Bestimmte Denkweise oder Art der Programmierung.

Berechnungsmodell und Programmstruktur[Bearbeiten | Quelltext bearbeiten]

2. Wozu dient ein Berechnungsmodell?[Bearbeiten | Quelltext bearbeiten]

Hinter jedem Paradigma ist ein Berechnungsmodell. Es muss turing-vollstandig sein (alle Berechnungen kénnen die auch ein Computer kann) und konsistent

3. Welche Berechnungsmodelle werden in Programmierparadigmen verwendet, und welche charakteristischen Eigenschaften haben sie?[Bearbeiten | Quelltext bearbeiten]

Funktionen
primitiv-rekursive
Pradikatenlogik
vor allem in Datenbanken
Constraint-Programmierung
x<5 oder A oder B ist wahr (heute werden dafür fertige Bibliotheken verwendet)
Temporale Logik und Petri-Netze
Freie Algebren
stark vereinfachte Algebren (einfache Axiome)
Prozesskalküle
Automaten
werden heute vorwiegend noch wegen der guten verstandlichkeit verwendet
WHILE, GOTO und Co
z.B.: bei MIPS nur LOOP und END LOOP

4. Welche Eigenschaften von Berechnungsmodellen sind für deren Erfolg häufig (mit)bestimmend?[Bearbeiten | Quelltext bearbeiten]

Universell einsetzbar, Abstraktion, Beharrungsvermögen, konsistenz

5. Im Spannungsfeld welcher widersprüchlichen Ziele befinden sich Programmierparadigmen? Wie äußert sich dieses Spannungsfeld?[Bearbeiten | Quelltext bearbeiten]

Flexibilität, Lesbarkeit, verständlich (Man will alles beschreiben aber es soll noch übersichtlich bleiben)

6. Was ist die strukturierte Programmierung? Wozu dient sie?[Bearbeiten | Quelltext bearbeiten]

Besteht aus drei Kontrollstrukturen: Sequenz (eins nach dem anderen), Auswahl (if, else), Wiederholung (Schleife, Rekursion) Bringt Struktur in Programmierung und bessere Lesbarkeit

7. Wie gehen unterschiedliche Paradigmen mit Seiteneffekten um?[Bearbeiten | Quelltext bearbeiten]

  • Deklarative Paradigmen: radikaler Ansatz = referentiell transparent (f{x)+f(x) = 2 f(x))
  • Objektorientierte Paradigmen: Querverbindungen werden lokal auf einzelne Objekte beschränkt.

8. Was bedeutet referentielle Transparenz, und wo findet man referentielle Transparenz?[Bearbeiten | Quelltext bearbeiten]

Ein Ausdruck ist referentiell transparent wenn er durch seinen Wert ersetzt werden kann ohne die Semantik des Programms zu ändern (3+4 => 7)

9. Wieso passt referentielle Transparenz nicht gut mit Ein- und Ausgabe zusammen, und wie kann man das Dilemma lösen?[Bearbeiten | Quelltext bearbeiten]

Weil Ein- und Ausgabe auch Seiteneffekte sind => wird nur ganz oben in der Aufrufhierarchie erlaubt

10. Welchen Zusammenhang gibt es zwischen Seiteneffekten und der objektorientierten Programmierung?[Bearbeiten | Quelltext bearbeiten]

Siehe 7)

11. Was sind First-Class-Entities? Welche Gründe sprechen für deren Verwendung, welche dagegen?[Bearbeiten | Quelltext bearbeiten]

Funktionen können wie normale Daten verwendet werden => in Variablen ablegen usw.. Sind komplizierter aber können als Kontrollstrukturen verwendet werden (Funktionen in Funktionen)

12. Was haben Funktionen höherer Ordnung mit einem applikativen Programmierstil zu tun?[Bearbeiten | Quelltext bearbeiten]

Es können Schablonen mit Löchern geschrieben werden die dann durch die Übergabe von Funktionen (zum Füllen der Löcher ausführbar werden)

Programmorganisation[Bearbeiten | Quelltext bearbeiten]

13. Welche Modularisierungseinheiten gibt es, was sind ihre charakteristischen Eigenschaften, und wodurch unterscheiden sie sich?[Bearbeiten | Quelltext bearbeiten]

Objekte
(Zustand, Identität, Verhalten) Daten Kapselung und Data Hiding = Datenabstraktion
Klassen
Schablone für neue Objekte
Komponente
eigenständiges Stück Software dass nur mit anderen Komponenten richtig funktioniert. Bei Übersetzungszeit ist offen von wo importierte Inhalte kommen
Namensraum
fassen Modularisierungseinheiten zusammen ohne die getrennte Übersetzbarkeit zu zerstören. => z.B.: a.b.C (Klasse C im Namensraum b, welcher im Namensraum a steht)

14. Welche Bedeutung haben Schnittstellen für Modularisierungseinheiten? Warum unterscheidet man zwischen von außen zugreifbaren und privaten Inhalten?[Bearbeiten | Quelltext bearbeiten]

Zusammengefasst Informationen über Inhalte des Moduls, die auch in anderen Modulen verwendbar sind. Private Inhalte können vom compiler beliebig optimiert werden. Von außen zugreifbare können nicht beliebig verändert werden da sie mit anderen Modulen zusammenarbeiten und somit auch die anderen Module geändert werden müssten.

15. Was ist und wozu dient ein Namensraum?[Bearbeiten | Quelltext bearbeiten]

Ein Namensraum gilt pro Modul. Das heißt die Namen müssen nur in diesem Namensraum eindeutig sein. In anderen Modulen/Namensräumen können dieselben Namen verwendet werden. Beim Import kann man Namenskonflikte durch Umbenennungen vermeiden.

16. Warum können Module nicht zyklisch voneinander abhängen, Komponenten aber schon?[Bearbeiten | Quelltext bearbeiten]

Weil Module getrennt übersetzt werden. Wenn A von B abhängt muss B vor A übersetzt werden. Wenn jetzt B auch von A abhängen würde hätten wir einen Deadlock. Diese Abhängigkeiten kann man mit der Aufteilung eines Moduls in Schnittstelleninformation und Implementierung aufteilt. (z.B.: Interfaces und Klassen (die die Interfaces implementieren)) Weil bei Komponenten erst zur Laufzeit bestimmt wird von wo importierte Inhalte kommen.

17. Was versteht man unter Datenabstraktion, Kapselung und DataHiding?[Bearbeiten | Quelltext bearbeiten]

  • Datenkapselung ist die Verschmelzung von zusammengehörigen Daten in eine Einheit.
  • DataHiding versteckt private Inhalte vor dem Zugriff von außen.
  • Datenabstraktion = Datenkapselung + DataHiding

18. Warum und inwiefern ist die Einbindung von Komponenten komplizierter als die von Modulen?[Bearbeiten | Quelltext bearbeiten]

Während Module getrennt voneinander als eigene selbstständige Einheiten angesehen werden können, interagieren Komponenten untereinander. Außerdem wird bei Komponenten erst zur Laufzeit klar von wo importiert wird.

19. Wie kann man globale Namen verwalten?[Bearbeiten | Quelltext bearbeiten]

Es wird ganz den Softwareentwicklern überlassen. Man mussalle Dateien anführen die die Modularisierungseinheiten enthalten. Oft helfen standardmäßig vorgegebene Verzeichnisse in denen automatisch nach verwendeten Modul- oder Klassennamen gesucht wird.

20. Was versteht man unter Parametrisierung? Wann kann das Befüllen von „Lücken“ durch welche Techniken erfolgen?[Bearbeiten | Quelltext bearbeiten]

In Modulen werden Löcher gelassen, die erst später gefüllt werden.

Zur Laufzeit
  • Konstruktor
  • Initialsierungsmethoden (z.B.: beim Kopieren von Objekten)
  • Zentrale Ablage (globale Variablen die erst zur Laufzeit abgeholt werden (z.B.: durch einfachen Zugriff oder Methoden)
Generizität

Füllung der Löcher zur Übersetzungszeit. Man programmiert so dass mehrere Typen verwendet werden können. Einschränkungen lassen sich schwer umsetzen da es sich nicht um First-Class-Entities handet.

Annotationen

@Override etc. Es lässt sich erfragen mit welcher Annotation etwas versehen ist (dynamisch zur Laufzeit) und können so den Programmablauf steuern. Oft wird dieses Konzept eingesetzt wenn Annotationen nicht nur von lokaler Bedeutung sind. (sondern auch Systemwerkzeuge)

Aspekte

Ein Aspekt spezifiziert gewisse Punkte im Programm und was an diesen Stellen passieren soll. Ein Aspect Weaver modifiziert das Programm entsprechend den Aspekten. (z.B.: Debugging, Logging)

21. Warum braucht man zur Parametrisierung in der Objekterzeugung neben Konstruktoren gelegentlich auch Initialisierungsmethoden?[Bearbeiten | Quelltext bearbeiten]

Weil Objekte auch kopiert werden können.

22. Welche Vor- und Nachteile hat die zentrale Ablage von Werten zum Zweck der Parametrisierung?[Bearbeiten | Quelltext bearbeiten]

Sie ist auch für statische Modularisierungseinheiten verwendbar die bereits zur Übersetzungszeit feststehen.

23. Was unterscheidet Generizität von den verschiedenen Formen der Parametrisierung zur Laufzeit?[Bearbeiten | Quelltext bearbeiten]

Löcher werden bereits zur Übersetzungszeit gefüllt.

24. Was sind Annotationen und wozu kann man sie verwenden? Wodurch unterscheiden sie sich von Generizität?[Bearbeiten | Quelltext bearbeiten]

Die Löcher die durch Annotationen gefüllt werden sind im Gegensatz zur Generizität nirgends im Programm festgelegt => Art und Weise der Verwendung sehr unterschiedlich.

25. Was versteht man unter aspektorientierter Programmierung?[Bearbeiten | Quelltext bearbeiten]

(siehe Frage 20)

26. Wodurch unterscheidet sich Parametrisierung von der Ersetzbarkeit, und warum ist die Ersetzbarkeit von so zentraler Bedeutung?[Bearbeiten | Quelltext bearbeiten]

Während bei der Parametrisierung Änderungen an den Löchern auch gleich Änderungen an den einzusetzenden Dingen der Löcher nach sich ziehen, kann durch Ersetzbarkeit einfacher nachträgliche Änderungen einzelner Moduleinheiten erreicht werden.

27. Wann ist A durch B ersetzbar?[Bearbeiten | Quelltext bearbeiten]

Wenn der Austausch keinerlei Änderungen an Stellen nach sich zieht, an denen A verwendet wird.

28. Wodurch kann festgelegt sein, ob A durch B ersetzbar ist?[Bearbeiten | Quelltext bearbeiten]

Wenn die Schnittstelle von B dasselbe Beschreibt wie die Schnittstelle von A (aber die Schnittstelle von B kann mehr beschreiben als die von A)

29. Was ist die Signatur einer Modularisierungseinheit?[Bearbeiten | Quelltext bearbeiten]

Boolean Funktion(int x); => Signatur = Funktion(int)

Boolean Funktion(double x); => Signatur = Funktion(double)

Namen und Typen von Parametern

30. Wie verhält sich die Signatur einer Modularisierungseinheit zur Abstraktion, die durch diese Modularisierungseinheit gebildet wird?[Bearbeiten | Quelltext bearbeiten]

Zusätzlich zur Signatur werden Schnittstellen durch Namen und informelle Texte beschrieben.

31. Was sind Zusicherungen, und welche Rolle spielen sie für Modularisierungseinheiten?[Bearbeiten | Quelltext bearbeiten]

Genaue Beschreibung der Ewartung an die Modularisierungseinheiten. Vertrag zwischen Modularisierungseinheit (Server) und ihren Verwendern(Clients).

Vorbedingung
was können sich Server von den Clients erwarten?
Nachbedingung
was kann sich der Client vom Server erwarten?
Invarianten
welche Eigenschaften in konsit. Programmzuständen immer erfüllt sind.
History-Constraints
wie und v.a. in welcher Reihenfolge Clients mir Servern agieren können.

Typisierung[Bearbeiten | Quelltext bearbeiten]

32. Wann sind Typen miteinander konsistent, und was sind Typfehler?[Bearbeiten | Quelltext bearbeiten]

Wenn die Typen der Operanden mit den Operationen zusammenpassen. Sonst tritt ein Typfehler auf.

33. Wie schränken Typen die Flexibilität ein, und warum verwendet man Typen trotzdem?[Bearbeiten | Quelltext bearbeiten]

Die Einschränkung ist, dass wir uns für einen Typen entscheiden und diese Entscheidung zieht sich über das gesammte Programm. Damit sind wir nicht so flexibel wie bei einer dynamischen Sprache(Typprüfung erst zu Laufzeit), jedoch ergibt sich folgender Vorteil: verbessert Lesbarkeit, verbesserte Zuverlässigkeit des Programms.

34. Welche Gründe sprechen für den Einsatz statischer Typprüfungen, welche dagegen?[Bearbeiten | Quelltext bearbeiten]

Pro: Einmal getroffene Entscheidungen bleiben konsistent. Je früher Entscheidungen getroffen werden desto weniger ist zur Laufzeit zu tun. Typfehler werden früher erkannt, wo die Auswirkungen noch nicht so groß sind. Man ist dadurch aber auch eingeschränkter.

35. Was versteht man unter Typinferenz? Welche Gründe sprechen für bzw. gegen den Einsatz?[Bearbeiten | Quelltext bearbeiten]

Typinferenz spart das Anschreiben von Typen. Typinferenz und Ersetzbarkeit durch Untertypen verträgt sich nicht. (im selben Teil des Programms). Lesbarkeit kann dadurch sogar verbessert werden weil es nur dort eingesetzt wird wo der Typ eh glasklar ist.

36. Zu welchen Zeitpunkten können Entscheidungen getroffen werden (Typen und Entscheidungsprozesse)?[Bearbeiten | Quelltext bearbeiten]

Alle bedeutenden Entscheidungen hinsichtlich der Programmstruktur und des Programmablaufs werden jedoch schon vorher, bei der Programmerstellung getroffen. Zeitpunkte:

  • in der Sprachimplementierung z.B. int als 32-Bit definiert
  • Zum Zeitpunkt der Erstellung von Übersetzungseinheiten
  • Entscheidungen durch Parametrisierung erst bei der Einbindung vorhandener Module, Klassen oder Komponenten getroffen
  • Vom Compiler(meist nur Optimierungen)
  • Zur Laufzeit: Initialisierungsphase von der eigentlichen Programmausführung unterscheidbar.

37. Welchen Einfluss können Typen auf Entscheidungszeitpunkte haben?[Bearbeiten | Quelltext bearbeiten]

Frühere Entscheidungen machen dann zur Laufzeit weniger Arbeit. Sogar wenn man weiß, dass die Variable eine ganze Zahl enthält, muss der Compiler eine beliebige Referenz annehmen und zur Laufzeit eine dynamische Typprüfung durchführen.

38. Wie beeinflussen Typen die Planbarkeit weiterer Schritte?[Bearbeiten | Quelltext bearbeiten]

Wenn man weiß, dass eine Variable vom Typ int ist, braucht man kaum mehr Überlegungen darüber anstellen, welche Werte in der Variablen enthalten sein könnten. Statt auf Spekulationen baut man auf Wissen auf. Um sich auf einen Typ festlegen zu können, muss man voraussehen (also planen), wie bestimmte Programmteile im fertigen Programm verwendet werden. Man wird zuerst jene Typen festlegen, bei denen man kaum Zweifel an der künftigen Verwendung hat. → frühe Entscheidungen daher oft sehr stabil.

39. Was ist ein abstrakter Datentyp?[Bearbeiten | Quelltext bearbeiten]

Die Trennung zwischen Innenansicht und Außenansicht einer Modularisierungseinheit (Data- Hiding). Die nach außen hin sichtbaren Inhalte bestimmen die Verwendbarkeit der Modularisierungseinheit. Private Inhalte bleiben bei der Verwendung unbekannt und die gesamte Modularisierungseinheit daher auf gewisse Weise abstrakt. Hinter jeder Modularisierungseinheit steht ein abstraktes Konzept, das im Idealfall eine Analogie in der realen Welt hat.

40. Was unterscheidet strukturelle von nominalen Typen?[Bearbeiten | Quelltext bearbeiten]

Struktureller Typ
Typ der Modularisierungseinheit hängt nur von Namen, Parametertypen und Ergebnistypen der nach außen sichtbaren Modulinhalte abhängt
Nominaler Typ
Neben Signatur auch einen eindeutigen Namen. Der Typ eines Objekts entspricht dem Namen der Klasse von der das Objekt erzeugt wurde.

41. Warum verwenden wir in Programmiersprachen meist nominale Typen, in theoretischen Modellen aber hauptsächlich strukturelle?[Bearbeiten | Quelltext bearbeiten]

Man gibt jeder Modularisierungseinheit einen eigentlich nicht verwendeten Inhalt mit, dessen Name das Konzept dahinter beschreibt. Damit werden gleiche Signaturen für unterschiedliche Konzepte ausgeschlossen. Wegen dieser stets vorhandenen Möglichkeit zur Abstraktion werden in der Theorie überwiegend strukturelle Typen betrachtet. Beim Programmieren denkt man hauptsächlich in abstrakten Konzepten und selten an Signaturen daher nominale Typen

42. Wie hängen Untertypbeziehungen mit Ersetzbarkeit zusammen?[Bearbeiten | Quelltext bearbeiten]

Untertypen werden durch das Ersetzbarkeitsprinzip definiert. Ohne Ersetzbarkeit gibt es keine Untertypen. Faustregel: Ein Typ U ist Untertyp von Typ T wenn jedes Objekt von U überall verwendbar ist, wo ein Objekt von T erwartet wird.

43. Warum kann ein Compiler ohne Unterstützung durch Programmierer(innen) nicht entscheiden, ob ein nominaler Typ Untertyp eines anderen nominalen Typs ist?[Bearbeiten | Quelltext bearbeiten]

Für nominale Typen reichen einfache Regeln nicht aus. Abstrakte und daher den Regeln nicht zugängliche Konzepte lassen sich ja nicht automatisch vergleichen. In der Praxis muss man beim Programmieren explizit hinschreiben, welcher Typ Untertyp von welchem anderen ist.

44. Erklären Sie Einschränkungen bei Untertypbeziehungen zusammen mit statischer Typprüfung.[Bearbeiten | Quelltext bearbeiten]

Es gibt keine Möglichkeit, entsprechende Typen statisch zu prüfen. Dynamische Prüfungen sind natürlich möglich. Aus demselben Grund sind auch Wertebereichseinschränkungen im Allgemeinen nicht statisch prüfbar; das bedeutet z.B., dass int nicht als Untertyp von long betrachtet werden kann, obwohl jede Zahl in int auch in long vorkommt.

45. In welchem Zusammenhang verwendet man Higher-Order-Subtyping und F-gebundene Generizität?[Bearbeiten | Quelltext bearbeiten]

Einfache Generizität ist leicht zu verstehen und auch vom Compiler leicht handzuhaben. Die Komplexität steigt jedoch rasch an, wenn man Einschränkungen auf Typparametern berücksichtigt, die vor allem (aber nicht nur)in der objektorientierten Programmierung benötigt werden. Im Wesentlichen gibt es zwei etwa gleichwertige formale Ansätze dafür: F-gebundene Generizität nutzt Untertypbeziehungen zur Beschreibung von Einschränkungen und wird z.B. in Java und C# eingesetzt. HigherOrder-Subtyping, auch Matching genannt, geht einen eher direkten Weg und beschreibt Einschränkungen über Untertyp-ähnliche Beziehungen, die wegen Unterschieden in Details aber keine Untertypbeziehungen sind.

46. Wie konstruiert man rekursive Datenstrukturen?[Bearbeiten | Quelltext bearbeiten]

Mittels induktiven Konstruktionen; Mengenvereinigung

47. Was versteht man unter Fundiertheit rekursiver Datenstrukturen? Welche Ansätze dazu kann man unterscheiden?[Bearbeiten | Quelltext bearbeiten]

Man muss klar zwischen MO (nicht-rekursiv) und der Konstruktion aller Mi mit i > O (rekursiv) unterscheiden, wobei MO nichtleer sein darf. Diese Eigenschaft nennt man Fundiertheit In Haskell muss es in jeder Typdefinition zumindest eine nicht-rekursive Alternative (z.B. end in Lst) geben. Die Menge MO ist etwa in Java schon in der Sprachdefinition vorgegeben und enthält nur den speziellen Wert null

48. Warum wird Typinferenz in objektorientierten Sprachen meist nur lokal beschränkt eingesetzt?[Bearbeiten | Quelltext bearbeiten]

Typinferenz funktioniert nicht, wenn gleichzeitig (also an derselben Stelle im Programm) Ersetzbarkeit durch Untertypen verwendet wird.

49. Wie können statisch geprüfte Typen beliebige Eigenschaften von Werten propagieren?[Bearbeiten | Quelltext bearbeiten]

Eine Funktion kann nur aufgerufen werden, wenn der Typ des Arguments mit dem des formalen Parameters übereinstimmt. Dabei wird Information über das Argumentan die aufgerufene Funktion propagiert. Entsprechendesgilt auch für das Propagieren von Information von der aufgerufenen Funktion zur Stelle des Aufrufs unter Verwendung des Ergebnistyps und bei der Zuweisung eines Wertes an eine Variable. Genau diese Art des Propagierens von Information funktioniert nicht nur für Typen im herkömmlichen Sinn, sondern für alle statisch bekannten Eigenschaften.

Objektorientierte Programmierung[Bearbeiten | Quelltext bearbeiten]

50. Erklären Sie folgende Begriffe:[Bearbeiten | Quelltext bearbeiten]

  • Objekt, Klasse, Vererbung
  • Identität, Zustand, Verhalten, Schnittstelle
  • deklarierter, statischer und dynamischer Typ
  • Faktorisierung, Refaktorisierung
  • Verantwortlichkeiten, Klassenzusammenhalt, Objektkopplung


51. Welche Arten von Polymorphismus unterscheidet man? Welche davon sind in der objektorientierten Programmierung wichtig? Warum?[Bearbeiten | Quelltext bearbeiten]

Universeller Polymorphismus: Generezität, Untertypen

Ad-hoc-Polymorphismus: Überladen, Typumwandlung

In der objektorientierten Programmierung sind Untertypen von überragender Bedeutung, die anderen Arten des Polymorphismus existieren eher nebenbei. Daher nennt man alles, was mit Untertypen zu tun hat, oft auch objektorientierten Polymorphismus oder nur kurz Polymorphismus.

52. Wann sind zwei gleiche Objekte identisch und wann sind zwei identische Objekte gleich?[Bearbeiten | Quelltext bearbeiten]

Zwei durch verschiedene Variablen referenzierte Objekte sind identisch wenn es sich um ein und dasselbe Objekt handelt. Zwei Objekte sind gleich wenn sie denselben Zustand und dasselbe Verhalten haben, auch wenn sie nicht identisch sind. In diesem Fall ist ein Objekt eine Kopie des anderen. Zustandsgleichheit: Wenn die Parameter gleich sind (wird mit equals verglichen) Ident: Wenn es sich um das identische Objekt, also das selbe Abbild im Speicher, handelt (wird mit == verglichen)

53. Sind Datenabstraktion, Datenkapselung und Data-Hiding einander entsprechende Begriffe? Wenn Nein, worin unterscheiden sie sich?[Bearbeiten | Quelltext bearbeiten]

Datenabstraktion und Datenkapselung sind komplimentäre Konzepte: Während sich die Abstraktion auf das von außen sichtbare fokusiert, beschäftigt sich die Kapselung mit der eigentlichen Implementierung, welche die Geheimnisse und Implementierungsdetails oft mit Data-Hiding archiviert.

54. Was besagt das Ersetzbarkeitsprinzip? (Häufige Prüfungsfrage!)[Bearbeiten | Quelltext bearbeiten]

Ein Typ U ist Untertyp eines Typs T, wenn jedes Objekt von U überall verwendbar ist wo ein Objekt von T erwartet wird.

55. Warum ist Ersetzbarkeit in der objektorientierten Programmierung so wichtig (mehrere Gründe)?[Bearbeiten | Quelltext bearbeiten]

Eine Möglichkeit zur praxistauglichen nachträglichen Änderung von Modularisierungseinheiten verspricht der Einsatz von Ersetzbarkeit statt oder zusätzlich zur Parametrisierung: Aufgrund der hohen Code-Wiederverwendung. Ohne Ersetzbarkeit keine Untertypen.

56. Wann und warum ist gute Wartbarkeit wichtig?[Bearbeiten | Quelltext bearbeiten]

Da Wartungskosten ca. 70 % der Gesamtkosten ausmachen. Gute Wartbarkeit erspart Unmengen an Geld! Wenn das Programm öfter verwendet wird

57. Wie lauten die wichtigsten Faustregeln im Zusammenhang mit Klassenzusammenhalt und Objektkopplung? Welche Vorteile kann man sich davon erwarten, dass diese Faustregeln erfüllt sind?[Bearbeiten | Quelltext bearbeiten]

Der Klassenzusammenhang soll hoch sein & Die Objektkopplung soll schwach sein gute Faktorisierung, Wahrscheinlichkeit geringer, dass bei Programmänderung auch die Zerlegung in Klassen und Objekte geändert werden muss.

58. Welche Arten von Software kann man wiederverwenden, und welche Rolle spielt jede davon in der Softwareentwicklung?[Bearbeiten | Quelltext bearbeiten]

  • Programme: werden oft genau für häufige (wieder)verwendung entwickelt
  • Daten: oft überdauern Daten die Lebensdauer der Programme.
  • Erfahrungen: können zwischen sehr unterschiedlichen Projekten ausgetauscht werden.
  • Code: Konzepte v. Untertypen, Vererbung und Generizität wurden im Hinblick für Code Wiederverwendung entwickelt. Man unterscheidet folgende Arten der Wiederverwendung: Bibliotheken, Projektinterne- oder Programminterne Wiederverwendung.

59. Welche Rolle spielen Refaktorisierungen in der Wiederverwendung?[Bearbeiten | Quelltext bearbeiten]

Refaktorisierungen ermöglichen das Hinführen des Projektes auf ein stabiles gut faktorisiertes Design. Gute Faktorisierung => starken Klassenzusammenhalt => gut abgeschlossene und somit leicht wiederverwendbare Klassen. Sie ändert die Struktur eines Programms,lässt aber dessen Funktionalität unverändert. Faustregel: Ein vernünftiges Maß rechtzeitiger Refaktorisierungen führt häufig zu gut faktorisierten Programmen und dadurch zu stabilen Klassen die für Vererbung und Untertypbeziehungen wichtig sind.

60. Wofür ist die objektorientierte Programmierung gut geeignet, und wofür ist sie nicht gut geeignet?[Bearbeiten | Quelltext bearbeiten]

Wenn Algorithmen zentral im Mittelpunkt stehen ist sie nicht gut geeignet. OOP steht die Datenabstraktion im Mittelpunkt, aber Algorithmen müssen unter Umständen aufwendig auf mehrere Objekte aufgeteilt werden. Das kann den Entwicklungsaufwand von Algorithmen erhöhen und deren Verständlichkeit verringern.

Faustregel: Objektorientierte Programmierung eignet sich zur Entwicklung von Systemen, deren Gesamtkomplexität jene der einzelnen Algorithmen deutlich übersteigt. Sonst sind andere Paradigmen besser geeignet.

Untertypen und Vererbung[Bearbeiten | Quelltext bearbeiten]

1. In welchen Formen (mindestens zwei) kann man durch das Ersetzbarkeitsprinzip Wiederverwendung erzielen?[Bearbeiten | Quelltext bearbeiten]

  • Erweiterung, jedoch beibehalten der Schnittstelle
  • Ersetzbarkeit (Faktorisierung)
  • interne Code-Wiederverwendung

2. Wann ist ein struktureller Typ Untertyp eines anderen strukturellen Typs? Welche Regeln müssen dabei erfüllt sein? Welche zusätzliche Bedingungen gelten für nominale Typen bzw. in Java? (Hinweis: Häufige Prüfungsfrage!)[Bearbeiten | Quelltext bearbeiten]

Allgemein gilt:

  • reflexiv (jeder ist sich selbst ein Untertyp)
  • transitiv (Untertyp von Untertyp ist Untertyp)
  • antisymmetrisch (wenn wechselseitige Untertypbeziehung, dann Gleichheit)

Generell gilt:

  • Konstante in T hat auch Konstante in U
  • Variable in T hat Variable in U (deklarierter Typ ist gleich)
  • Methode in T hat Methode in U (Ergebnistypen kovariant, gleiche Parameteranzahl, *Eingangsparameter kontravariant [in Java bedeutet das sonst überladen])
Kovarianz
Untertyp oder gleich des deklarierten Typs
Invarianz
gleicher Typ
Kontravarianz
Obertyp oder gleich des deklarierten Typs

3. Sind die in Punkt 2 angeschnittenen Bedingungen (sowie das, was Compiler prüfen können) hinreichend, damit das Ersetzbarkeitsprinzip erfüllt ist? Wenn nicht, was muss noch beachtet werden?[Bearbeiten | Quelltext bearbeiten]

Ja, wenn das Verhalten nicht berücksichtigt wird (vgl. Zusicherungen). Sonst Nein.

4. Was bedeutet Ko-, Kontra- und Invarianz, und für welche Typen in einer Klasse trifft welcher dieser Begriffe zu? (Hinweis: Häufige Prüfungsfrage!)[Bearbeiten | Quelltext bearbeiten]

5. Was sind binäre Methoden, und welche Schwierigkeiten verursachen sie hinsichtlich der Ersetzbarkeit?[Bearbeiten | Quelltext bearbeiten]

Eine Methode, bei der ein formaler Parametertyp stets gleich der Klase ist, in der die Methode definiert ist, heißt *binär*.

> **Faustregel**: Kovariante Eingangsparametertypen und binäre Methoden widersprechen dem Ersetzbarkeitsprinzip. Es ist sinnlos, in solchen Fällen Ersetzbarkeit anzustreben.

(Die Eigenschaft binär bezieht sich darauf, dass der Name der Klasse in der Methode mindestens zweimal vorkommt – einmal als Typ von this und mindestens einmal als Typ eines formalen Parameters.)

6. Wie soll man Typen formaler Parameter wählen um gute Wartbarkeit zu erzielen?[Bearbeiten | Quelltext bearbeiten]

> **Faustregel**: Man soll Parametertypen vorausschauend und möglichst allgemein wählen.

7. Warum ist dynamisches Binden gegenüber switch- oder geschachtelten if-Anweisungen zu bevorzugen?[Bearbeiten | Quelltext bearbeiten]

8. Dient dynamisches Binden der Ersetzbarkeit und Wartbarkeit?[Bearbeiten | Quelltext bearbeiten]

Durch dynamisches Binden können Optionen (Unterklassen) einfach hinzugefügt/entfernt werden, ohne die Struktur der anderen Klassen zu ändern.

9. Welche Arten von Zusicherungen werden unterschieden, und wer ist für die Einhaltung verantwortlich? (Hinweis: Häufige Prüfungsfrage!)[Bearbeiten | Quelltext bearbeiten]

  • Vorbedingungen (@param,“Welche Eigenschaften sollen die Eingangsparameter haben?“)
  • Nachbedingungen (@result, „Was sagt das Ergebnis aus?“)
  • Invarianten (Gelten für alle Methoden, Zuständigkeit des Servers)
  • History-Constraint: schränken die Entwicklung von Objekten im Laufe der Zeit ein.
    • Server-kontrolliert: wie Invarianten. Z.B. ganzzahlige Zähler kann im Laufe der Zeit nur größer werden.
    • Client-kontrolliert: Reihenfolge der Methodenaufrufe einschränken. Z.B. Methode "Initialize" kann in jedem Objekt nur einmal aufgerufen werden.

Grundsätzlich ist der Programmierer für die Einhaltung der Zusicherungen verantwortlich. Hinweis: In Java sind Zusicherungen nur durch Kommentare auszudrücken.

10. Wie müssen sich Zusicherungen in Unter- und Obertypen zueinander verhalten, damit das Ersetzbarkeitsprinzip erfüllt ist? Warum? (Hinweis: Häufige Prüfungsfrage!)[Bearbeiten | Quelltext bearbeiten]

→ Vorbedingungen kovariant → Nachbedinungen kontravariant

Zusicherungen des Obertyps müssen auch für den Untertypen gelten.

11. Warum sollen Signaturen und Typen stabil bleiben? Wo ist Stabilität besonders wichtig?[Bearbeiten | Quelltext bearbeiten]

Bewahrung der (Abwärts-)Kompatibilität. Vor allem an der „Wurzel“ von Klassenhierarchien wichtig (allgemeine Typen). Gilt auch für Zusicherungen.

12. Was ist im Zusammenhang mit allgemein zugänglichen (= möglicherweise nicht nur innerhalb des Objekts geschriebenen) Variablen und Invarianten zu beachten?[Bearbeiten | Quelltext bearbeiten]

Sie müssen in Zusicherungen bedacht werden.

13. Wie genau sollen Zusicherungen spezifiziert sein?[Bearbeiten | Quelltext bearbeiten]

Als zum Typ (=Name+Schnittstelle+Zusicherungen) gehörend. Aber keine unnötigen Details.

14. Wozu dienen abstrakte Klassen und abstrakte Methoden? Wo und wie soll man abstrakte Klassen einsetzen?[Bearbeiten | Quelltext bearbeiten]

Von abstrakten Klassen können keine Instanzen erzeugt werden, abstrakte Methoden müssen in Unterklassen implementiert werden. Hauptvorteil zum Interface ist die Code-Wiederverwendung. (ermöglichen auch Dinge wie das Pattern „Template-Method“)

15. Ist Vererbung das gleiche wie das Ersetzbarkeitsprinzip? Wenn Nein, wo liegen die Unterschiede?[Bearbeiten | Quelltext bearbeiten]

Nein, Vererbung = Erweitern und Überschreiben Ersetzbarkeitsprinzip = Das Auftreten eines Elements kann durch ein anderes ersetzt werden

Eine Vererbungshierarchie garantiert allerdings in Java auch, dass das Ersetzbarkeitsprinzip erfüllt ist.

16. Worauf kommt es zur Erzielung von Codewiederverwendung eher an, auf Vererbung oder Ersetzbarkeit? Warum?[Bearbeiten | Quelltext bearbeiten]

Die Wiederverwendung durch das Ersetzbarkeitsprinzip (bestehen expliziter Untertypbeziehungen) ist wesentlich wichtiger als die Wiederverwendbarkeit von Code durch Vererbung (Allerdings kann nur durch Vererbung Code direkt vererbt werden).

17. Was bedeuten folgende Begriffe in Java?[Bearbeiten | Quelltext bearbeiten]

  • Objektvariable, Klassenvariable, statische Methode
  • Static-Initializer
  • geschachtelte und innere Klasse
  • final Klasse und final Methode
  • Paket, Class-Path, import-Anweisung

18. Wo gibt es in Java Mehrfachvererbung, wo Einfachvererbung?[Bearbeiten | Quelltext bearbeiten]

Mehrfachvererbung mittels Interfaces, keine echte Mehrfachvererbung.

19. Welche Arten von import-Deklarationen kann man in Java unterscheiden? Wozu dienen sie?[Bearbeiten | Quelltext bearbeiten]

  • import Classname; // ganze Klasse
  • import paket.*; // alle in diesem Ordner
  • import Datei; // diesen Pfad bis zu diesem Punkt importieren

20. Wozu benötigt man eine package-Anweisung?[Bearbeiten | Quelltext bearbeiten]

21. Welche Möglichkeiten zur Spezifikation der Sichtbarkeit gibt es in Java, und wann soll man welche Möglichkeit wählen?[Bearbeiten | Quelltext bearbeiten]

  • public – überall sichtbar, vererbbar
  • protected – in anderem Paket nicht sichtbar, aber vererbbar
  • default – nur im momentanen Paket sichtbar, vererbbar
  • private – nur in dieser Klasse

22. Wodurch unterscheiden sich Interfaces in Java von abstrakten Klassen? Wann soll man Interfaces verwenden? Wann sind abstrakte Klassen besser geeignet?[Bearbeiten | Quelltext bearbeiten]

Interfaces (abstrakte Klassen zur Mehrfachvererbung, keine konkreten Implementierungen) haben Einschränkungen. Sie enthalten keinen Code, Zusicherungen sind essential für die Wahrung ihrer Integrität (nur abstrakte Methoden).

Abstrakte Klassen sind konkret, haben Code-Vererbung. Sollten verwendet werden wenn genau dies nötig ist, ansonsten sind Interfaces (Untertypbeziehungen) immer besser und wichtiger.

Generizität und Ad-hoc-Polymorphismus[Bearbeiten | Quelltext bearbeiten]

1. Was ist Generizität? Wozu verwendet man Generizität?[Bearbeiten | Quelltext bearbeiten]

Generische Klassen, Typen und Routinen (Methoden) erhalten Typparameter die für Typen eingesetzt werden können. Damit ist Generizität eine weitere Form des universellen Polymorphismus, die Wiederverwendung unterstützen kann.

Zweck: Wartbarkeit, Sicherheit, Wiederverwendung, Lesbarkeit

2. Was ist gebundene Generizität? Was kann man mit Schranken auf Typparametern machen, das ohne Schranken nicht geht?[Bearbeiten | Quelltext bearbeiten]

Wenn zusätzliche Information über Typparameter nötig ist, benötigt man Schranken. Der Typparameter erweitert eine Schrankenklasse (Klasse <Typparameter extends Class>), kann als Typ der Schranke bei Zugriffen verwendet werden.

3. In welchen Fällen soll man Generizität einsetzen, in welchen nicht?[Bearbeiten | Quelltext bearbeiten]

Pro
  • Wartbarkeit
  • Typsicherheit
  • Gleich strukturierte Klassen/Routinen (z.B. Containerklassen, Libraries)
  • leichtere Code-Änderungen
Kontra
  • kann Untertypbeziehungen nicht ersetzen
  • wenn keine Notwendigkeit besteht

4. Was bedeutet statische Typsicherheit in Zusammenhang mit Generizität, dynamischen Typabfragen und Typumwandlungen?[Bearbeiten | Quelltext bearbeiten]

Der Compiler garantiert dass in Instanzen vom Typ <String> auch nur Strings eingefügt werden / enthalten sind. Typinferenz: Vorgang zur Berechnung der Typen.


5. Was sind (gebundene) Wildcards als Typen in Java? Wozu kann man sie verwenden?[Bearbeiten | Quelltext bearbeiten]

Einsatz als Typparameter bzw. Schranken in Methoden (<? extends/super Class>).

  • Lesezugriffe fordern in solchen Methoden Kovarianz (from)
  • Schreibzugriffe fordern Kontravarianz (to)

6. Welche Arten von Generizität kann man hinsichtlich ihrer Übersetzung und ihrem Umgang mit Schranken unterscheiden? Welche Art wird in Java verwendet, und wie flexibel ist diese Lösung?[Bearbeiten | Quelltext bearbeiten]

homogene Übersetzung
  • 1 generische Klasse bedeutet -> 1 nicht-generische Klasse
  • der Compiler garantiert Typsicherheit
  • wird in Java verwendet
heterogene Übersetzung
  • 1 generische Klasse -> n nicht-generische Klassen (für jede wird eine erzeugt)
  • bessere Laufzeiteffizienz

Beim Übersetzungsvorgang werden alle Ausdrücke in spitzen Klammern vernichtet und durch Type-Casting ersetzt.

7. Wie kann man Generizität simulieren? Worauf verzichtet man, wenn man Generizität nur simuliert?[Bearbeiten | Quelltext bearbeiten]

Simulierte Generizität (Klonen der Klassen) führt zu mehrfachen Klassen und erschwert somit die Wartbarkeit.

8. Was wird bei der heterogenen bzw. homogenen Übersetzung von Generizität genau gemacht?[Bearbeiten | Quelltext bearbeiten]

Die generischen Klassen werden vom Compiler umgewandelt in normale Klassen, welche Type Casting verwenden (homogen) oder für alle relevanten Untertypen erzeugt werden (heterogen).

9. Was muss der Java-Compiler überprüfen um sicher zu sein, dass durch Generizität keine Laufzeitfehler entstehen?[Bearbeiten | Quelltext bearbeiten]

10. Welche Möglichkeiten für dynamische Typabfragen gibt es in Java, und wie funktionieren sie genau?[Bearbeiten | Quelltext bearbeiten]

  • getClass() – Klasse eines Objekts als Ergebnis
  • instanceof-Operator – ist das Objekt links eines Instanz des Objekts rechts?

11. Was wird bei einer Typumwandlung in Java umgewandelt – der deklarierte, dynamische oder statische Typ? Warum?[Bearbeiten | Quelltext bearbeiten]

Der deklarierte Typ wird umgewandelt in den gerade benötigten Typ im Programm (falls möglich). Compiler kennt nur den deklarierten Typ bzw. legt den statischen Typ fest, aber nicht den echten (dynamischen) Typ.

12. Welche Gefahren bestehen bei Typumwandlungen?[Bearbeiten | Quelltext bearbeiten]

Class Cast Exceptions

  • die statische Typ-Überprüfung durch den Compiler wird übergangen
  • schlechte Wartbarkeit beim Einsatz vieler Typumwandlungen

13. Wie kann man dynamische Typabfragen und Typumwandlungen vermeiden? In welchen Fällen kann das schwierig sein?[Bearbeiten | Quelltext bearbeiten]

Dynamisches Binden.

Schwierigkeiten:

  • bei sehr allgemeinen Typen (sollte vermieden werden)
  • Erweiterungen sind nicht erlaubt
  • wichtige private Methoden
  • sehr viele Untertypen werden benötigt

14. Welche Arten von Typumwandlungen sind sicher? Warum?[Bearbeiten | Quelltext bearbeiten]

  • Typumwandlungen auf primitive Datentypen sind sicher (haben anderen Zweck)
  • Umwandlungen in den Obertyp
  • nach dynamischen Typ-Abfragen („else-Zweig“ bedenken)
  • wenn Programmierer die Verwendung genau geprüft hat

Weil dann nichts schiefgehen kann.

15. Was sind kovariante Probleme und binäre Methoden? Wie kann man mit ihnen umgehen oder sie vermeiden?[Bearbeiten | Quelltext bearbeiten]

Kovariante Probleme: Treten auf wenn kovariante Eingangsparametertypen erwünscht sind. Das verletzt das Ersetzbarkeitsprinzip und sollte somit vermieden werden. Binäre Methoden: Empfangen einen Parameter der Klasse, der gleich der Klasse ist, was bei Vererbung zum Verhängnis wird.

→ keine gefährlichen Erweiterungen machen, lieber refaktorisieren

16. Wie unterscheidet sich Überschreiben von Überladen, und was sind Multimethoden?[Bearbeiten | Quelltext bearbeiten]

Überschreiben
Methode in Unterklasse überschreibt Methode in Oberklasse, sie wird also verwendet, egal welcher Typ deklariert ist
Überladen
Methode in Unterklasse koexisitiert zu Methode in Oberklasse (tritt bei Java immer auf wenn: Eingangsparameter nicht invariant, Ausgangsparameter nicht kovariant)
Multimethoden
Methoden sind zwar koexistent, jedoch ist der dynamische Typ entscheidend

Bei überladenen Methoden entscheidet stets der deklarierte Typ über das Verhalten, was unerwünschtes Verhalten hervorruft.

17. Wie kann man Multimethoden simulieren? Welche Probleme können dabei auftreten?[Bearbeiten | Quelltext bearbeiten]

Über mehrfaches dynamisches Binden. Es wird jedoch eine hohe Anzahl an Methoden benötigt.

18. Was ist das Visitor-Entwurfsmuster?[Bearbeiten | Quelltext bearbeiten]

Über mehrfaches dynamisches Binden werden Multi-Methoden simuliert.

Es gibt Visitorklassen (vgl. Futter) und Elementklassen (vgl. Tier).

Durch die Methode in der bestimmten Klasse, wird die richtige Methode in der korrespondierenden Klasse korrekt aufgerufen.

19. Wodurch ist Überladen problematisch, und in welchen Fällen ergeben sich kaum Probleme?[Bearbeiten | Quelltext bearbeiten]

Überladen ist dann problematisch, wenn die Namen gleich sind und zwischen den Parametern bei gleicher Typ-Anzahl Untertypbeziehungen bestehen. Das sollte vermieden werden.

Kreuz und quer[Bearbeiten | Quelltext bearbeiten]

1. Wie werden Ausnahmebehandlungen in Java unterstützt?[Bearbeiten | Quelltext bearbeiten]

Ausnahmen sind in Java gewöhnliche Objekte, die über spezielle Mechanismen als Ausnahmen verwendet werden. Alle Instanzen von Throwable sind dafür verwendbar. Praktisch verwendet man nur Instanzen der Unterklassen von Error und Exception, zwei Unterklassen von Throwable. Unterklassen von Error werden hauptsächlich für vordefinierte, schwerwiegende Ausnahmen des Java-Laufzeitsystems verwendet und deuten auf echte Fehler hin, die während der Programmausführung entdeckt wurden. Es ist praktisch kaum möglich, solche Ausnahmen abzufangen; ihr Auftreten führt fast immer zur Programmbeendigung.

2. Wie sind Ausnahmen in Untertypbeziehungen zu berücksichtigen?[Bearbeiten | Quelltext bearbeiten]

Exceptions die auftreten können werden im Methodenkopf hinter dem Stichwort throws aufgelistet. Sei U ein Untertyp von T. In U darf keine Exceptions werfen, die in T nicht definiert sind.

3. Wozu kann man Ausnahmen verwenden? Wozu soll man sie verwenden, wozu nicht?[Bearbeiten | Quelltext bearbeiten]

Dafür:

  • Unvorhergesehene Programmabbrüche
  • Kontrolliertes Wiederaufsetzen

Dafür nicht:

  • Ausstieg aus Sprachkonstrukten
  • Rückgabe alternativer Ergebniswerte

Generell sind Ausnahmen sparsam und wirklich nur in Ausnahmesituationen einzusetzen.

4. Durch welche Sprachkonzepte unterstützt Java die nebenläufige Programmierung? Wozu dienen diese Sprachkonzepte?[Bearbeiten | Quelltext bearbeiten]

Java unterstützt nebenläufige Programmierung durch die Verwendung mehrerer Threads. Threads dienen zum parallelen Bearbeiten von Ressourcen.

5. Wozu brauchen wir Synchronisation? Welche Granularität sollen wir dafür wählen?[Bearbeiten | Quelltext bearbeiten]

ei der Verwendung mehrerer Threads kann es wenn diese unkontrolliert auf Ressourcen zugreifen zu Inkonsistenzen, unerwarteten Folgen kommen,da nicht alle Threads gleichmäßig arbeiten. Eine gewisse Ressource (oder Methode) kann synchronisiert werden, damit immer nur ein Thread Zugriff darauf hat. Es ist die feinst-mögliche Granularität (Körnung) zu wählen, da Synchronisierung teuer bezüglich Laufzeit ist, da die anderen Transaktionen auf die momentan laufende warten müssen.

6. Zu welchen Problemen kann Synchronisation führen, und was kann man dagegen tun?[Bearbeiten | Quelltext bearbeiten]

Deadlocks
Zyklische Abhängigkeiten zwischen mehreren Threads
(Thread A wartet auf Thread B und B wiederum wartet auf A)
Lifelocks
Alle arbeiten, aber es geschieht nichts!

7. Wozu dienen Annotationen? Wann setzt man sie sinnvoll ein?[Bearbeiten | Quelltext bearbeiten]

8. Wie lange können Annotationen leben? Wofür ist welche Lebensdauer sinnvoll?[Bearbeiten | Quelltext bearbeiten]

9. Wie kann man eigene Annotationen deklarieren? Welche Gemeinsamkeiten und Unterschiede zu Interfaces bestehen?[Bearbeiten | Quelltext bearbeiten]

10. Wie kann man zur Laufzeit auf Annotationen zugreifen?[Bearbeiten | Quelltext bearbeiten]

11. Was ist aspektorientierte Programmierung? Wann setze ich sie sinnvoll ein?[Bearbeiten | Quelltext bearbeiten]

12. Was bedeutet Separation-of-Concerns?[Bearbeiten | Quelltext bearbeiten]

Die Aufteilung der Funktionalität eines Programmes auf einzelne Modularisierungeinheiten.

13. Was sind Core-Concerns, was Cross-Cutting-Concerns?[Bearbeiten | Quelltext bearbeiten]

Kernfunktionalitäten und Querschnittsfunktionalitäten.

14. Was sind Join-Points, Pointcuts, Advices und Aspekte, und wozu braucht man sie?[Bearbeiten | Quelltext bearbeiten]

Ein Join-Point ist eine identifizierbare Stelle während einer Programmausführung, z.B. der Aufruf einer Methode oder der Zugriff auf ein Objekt.

Ein Pointcut ist ein Programmkonstrukt, das einen Join-Point auswählt und kontextabhängige Information dazu sammelt, z.B. dieArgumente eines Methodenaufrufs oder das Zielobjekt.

Ein Advice ist jener Programmcode, der vor, um oder nach dem Join-Point ausgeführt wird.

Ein Aspekt ist wie eine Klasse das zentrale Element in AspectJ. Enthält alle Deklarationen, Methoden, Pointcuts und Advices.

15. An welchen Programmpunkten können sich Join-Points befinden?[Bearbeiten | Quelltext bearbeiten]

Software-Entwurfsmuster[Bearbeiten | Quelltext bearbeiten]

1. Erklären Sie folgende Entwurfsmuster und beschreiben Sie jeweils Anwendungsgebiet, Struktur, Eigenschaften und wichtige Details der Implementierung unter Verwendung vorgegebener Namen:[Bearbeiten | Quelltext bearbeiten]

Decorator
oder auch Wrapper genannt. Wir angewendet um dynamische Verantwortlichkeiten zu einzelnen Objekten hinzuzufügen ohne andere Objekte zu beeinflussen; um diese Verantwortlichkeiten auch wieder zu entziehen; wenn Erweiterungen einer Klasse durch Vererbung unpraktisch sind (sehr viele Unterklassen vermeiden) oder die Programmiersprache keine Vererbung unterstützt (bei final Klassen zB).
Factory-Method
oder Virtual-Constructor verschiebt erzeugung der Objekte in Unterklassen. Diese entscheiden, welche Unterklasse Objekt erzeugt. Eine Klasse soll Objekte erzeugen kennt aber deren Klasse nicht; eine Klasse möchte, das die Unterklassen die Art der zu erzeugenden Objekte bestimmen; Allokation und freihabe von Objekten sollen in einer klasse verwaltet werden. Anküpfungspunkte (HOOKS) für unterklassen, die überschreiben werden müsse parallele Klassenhierachien (Creator und Product Hierachien)
Iterator
um auf Inhalt eines Aggregats zugreifen zu können. Ohne innere Darstellung offen zu legen.
Prototype
spezifiziert den Prototyp eines neuerzeugten Objekts. Wenn Factory-Method vermieden werden soll; wenn die Klasse von der Objekte erzeugt werden sollen erst zur Laufzeit bekannt sind. Wenn jedes Objekt nur wenige zustände hat → für jeden Zustand einen Prototype
Proxy
oder auch Surrogate ist ein Platzhalter für eine anderes Objekt und kontrolliert die Zugriffe darauf. Remote-Proxies sind Platzhalter für Objekte in anderen Namensräumen (Festplatte, anderer Rechner). Virtual-Proxies erzeugen Objekte bei Bedarf. (Aufwendige erzeugung von Objekten) Protection-Proxies kontrolliert Zugriffe auf Objekte. Sinnvoll wenn Objekte je nach Zugreifer unterscheidliche Zugriffsrechte besitzen. Smart-Proxies ersetzen Zeiger. Zählen der zugriffen(reference counting), Objectlocking, laden von objekten aus persistenetem speicher.
Singleton
sichert zu, dass eine Klasse nur eine Instanz hat und erlaubt den zugriff auf das Objekt. Wenn die Klasse durch Vererbung erweiterbar sein soll.
Template-Method
definiert das Grundgerüt eines Algorithmus. Angewandt um den unveränderlichen teil nur einmal zu implementieren und veränderbares den Unterklassen zu überlassen oder auch gemeinsames verhalten zusammenzufassen. Template methods die HOOKS anbieten (überschreiben in unterklassen.)
Visitor
(siehe Abschnitt 3.4.2)

2. Welche Arten von Iteratoren gibt es, und wofür sind sie geeignet?[Bearbeiten | Quelltext bearbeiten]

Interne Iteratoren
Selbstkontrolle (leichterer Umgang)
Externe Iteratoren
vom Anwender benutzt (schlecht für komplexe Beziehungen und schwieriger zu steuern, aber flexibler)

3. Wie wirkt sich die Verwendung eines Iterators auf die Schnittstelle des entsprechenden Aggregats aus?[Bearbeiten | Quelltext bearbeiten]

Sie wird komplexer, da ein Iterator benötigt wird der gesteuert werden muss. Die interne Funktionalität des Aggregats wird versteckt.

4. Inwiefern können geschachtelte Klassen bei der Implementierung von Iteratoren hilfreich sein?[Bearbeiten | Quelltext bearbeiten]

Ein interner Iterator kann auf alle Variablen/Methoden der Oberklasse zugreifen, wodurch weniger Nachrichten nötig sind.

5. Was ist ein robuster Iterator? Wozu braucht man Robustheit?[Bearbeiten | Quelltext bearbeiten]

Ein Iterator der nicht kaputt gehen kann, wenn sich das Aggregat nach seiner Erzeugung verändert (durch Kopie des Aggregats oder gute Implementierung).

6. Wird die Anzahl der benötigten Klassen im System bei Verwendung von Factory-Method, Prototype, Decorator und Proxy (gegenüber einem System, das keine Entwurfsmuster verwendet) eher erhöht, vermindert oder bleibt sie unverändert?[Bearbeiten | Quelltext bearbeiten]

  • Factory Method: Erhöhung der Klassen
  • Prototype: Wird niedriger
  • Decorator: Steigt
  • Proxy: Steigt (leicht)

7. Wird die Anzahl der benötigten Objekte im System bei Verwendung von Factory-Method, Prototype, Decorator und Proxy (gegenüber einem System, das keine Entwurfsmuster verwendet) eher erhöht, vermindert oder bleibt sie unverändert?[Bearbeiten | Quelltext bearbeiten]

  • Factory Method: Bleibt gleich
  • Prototype: Bleibt gleich / steigt
  • Decorator: Steigt
  • Proxy: Bleibt gleich (Objekterzeugung nicht nötig) oder steigt

8. Vergleichen Sie Factory-Method mit Prototype. Wann stellt welches Entwurfsmuster die bessere Lösung dar? Warum?[Bearbeiten | Quelltext bearbeiten]

FM: Delegiert Erzeugung an Unterklassen, mühsam die Struktur zu erweitern

PR: Erzeugt Kopien von deklarierten Typen, mühsam die neu erzeugten Typen zu verwalten

9. Wo liegen die Probleme in der Implementierung eines so einfachen Entwurfsmusters wie Singleton?[Bearbeiten | Quelltext bearbeiten]

Entweder der Obertyp kennt alle Untertypen, oder die Untertypen müssen alle instance() implementieren.

10. Welche Unterschiede und Ähnlichkeiten gibt es zwischen Decorator und Proxy?[Bearbeiten | Quelltext bearbeiten]

Ein Proxy kann dieselbe Struktur wie ein Decorator haben. Aber Proxies dienen einem ganz anderen Zweck als Decorators: Ein Decorator erweitert ein Objekt um zusätzliche Verantwortlichkeiten, während ein Proxy den Zugriff auf das Objekt kontrolliert. Damit haben diese Entwurfsmuster auch gänzlich unterschiedliche Eigenschaften.

11. Welche Probleme kann es beim Erzeugen von Kopien im Prototype geben? Was unterscheidet flache Kopien von tiefen?[Bearbeiten | Quelltext bearbeiten]

Flache Kopie → alle Referenz-Variablen sind identisch

Tiefe Kopie → alles wird geklont (manchmal schwierig, problematische Zyklen)

12. Für welche Arten von Problemen ist Decorator gut geeignet, für welche weniger? (Oberfläche versus Inhalt)[Bearbeiten | Quelltext bearbeiten]

Gut um das Erscheinungsbild von Objekten zu verändern, schlecht für inhaltliche Änderungen.

13. Kann man mehrere Decorators bzw. Proxies hintereinander verketten? Wozu kann so etwas gut sein?[Bearbeiten | Quelltext bearbeiten]

Ja. Bei Decorators können auf diese Art und Weise z.B. umfangreiche GUIs gebildet werden. Bei Proxies gibt es beliebige Möglichkeiten, wie z.B. das Kapseln mehrerer Funktionalitäten.

14. Was unterscheidet Hooks von abstrakten Methoden?[Bearbeiten | Quelltext bearbeiten]

"hooks" werden benutzt um definierte Teile eines Algorithmus zur Veränderung in Unterklassen freizugeben. Einen Teil des Codes enthalten sie selbst. Abstrakte Methoden hingegen erhalten keinen Code, sie werden lediglich über Zusicherungen implementiert.