1 / 48

Software-Engineering II

Software-Engineering II. Analyse- und Entwurfsmuster. Themenübersicht. Objektorientierung Aspektorientierung Vorgehensmodelle UML Analyse- & Entwurfsmuster Objektorientiertes Testen Versionsverwaltung Refactoring Labor (Praktischer Teil).

kato-haley
Télécharger la présentation

Software-Engineering II

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Software-Engineering II Analyse- und Entwurfsmuster

  2. Themenübersicht Objektorientierung Aspektorientierung Vorgehensmodelle UML Analyse- & Entwurfsmuster Objektorientiertes Testen Versionsverwaltung Refactoring Labor (Praktischer Teil)

  3. Beschreiben Lösungen zu häufig wiederkehrenden Problemen Muster bieten jahrelang erprobte Lösungen die durch ihre Dynamik und Flexibilität herausstechen einheitliches Vokabular für die Arbeit im Team Muster (Patterns)

  4. Analysemuster Analysemuster Martin Fowler Addison-Wesley 386 Seiten ISBN: 3-8273-1434-8 (Deutsch)

  5. Finden ihren Haupteinsatz in der Analysephase Bieten in der Praxis bewährte Modellierungen von Standardzusammenhängen aus spezifischen Domänen Analysemuster

  6. Beispiel: Muster „Party“ Fowler: Die Bezeichnung Party soll immer dann verwendet werden, wenn bei der Modellierung eine Generalisierung von Person und Organisation gesucht wird. Bsp. aus der Domäne: Adressverwaltung Adressbuch: In ihrem Adressbuch speichert eine Firma sowohl Privatpersonen als auch Organisationen. Beide Entitäten besitzen gleiche Eigenschaften: - Post-Anschrift - Telefon-Nummer - E-Mail-Adresse Die Entität Party soll einen Oberbegriff für diese Entitäten bilden.

  7. Entwurfsmuster Head First Design Patterns Eric Freeman, Elisabeth Freeman, Kathy Sierra, Bert Bates O‘Reilly 638 Seiten ISBN: 0-5960-0712-4 (Englisch) ISBN: 3-8972-1421-0 (Deutsch)

  8. Entwurfsmuster Design Patterns Elements of Reusable Object-Oriented Software „Gang of Four“ Addison-Wesley 395 Seiten ISBN: 0-2016-3361-2 (Englisch) (Die deutsche Ausgabe wird nicht empfohlen)

  9. Einsatz: Entwurfs- und Implementierungsphase Objektorientierte Klassenmodelle, die erprobte, generische Lösungen bieten Lösen wiederkehrende Probleme Helfen, erweiterbaren und damit wieder verwendbaren Code zu schreiben Bieten Vokabular für Software-Ingenieure Programmiersprachenunabhängig Entwurfsmuster

  10. Das Singleton-Pattern

  11. Die Berufsakadie • Situation: Es kann nur eine geben! • Es muss verhindert werden, dass mehrere Instanzen der Klasse erzeugt werden, da die Berufsakademie unser zentrales Verwaltungsobjekt darstellt class x { … ba.addSemester( new Semester( ‘TIT2005 ‘ ) ); } class y { … ba.addSemester( new Semester( ‘TIT2006‘ ) ); // Muss dieselbe // Instanz sein!!! }

  12. Die Instanz der Berufsakademie wird in einem statischen Attribut der Klasse gespeichert Ansatz: Statisches Attribut Bei jedem Zugriff: //--- if( Berufsakademie.instance == null ) { Berufsakademie.instance = new Berufsakademie(); } //--- Berufsakademie.instance.addSemester( … );

  13. Das herkömmliche Instanzieren (new) wird nicht verhindert! Das Initialisieren kann leicht vergessen werden! Ansatz: Statisches Attribut Bei jedem Zugriff: //--- if( Berufsakademie.instance == null ) { Berufsakademie.instance = new Berufsakademie(); } //--- Berufsakademie.instance.addSemester( … );

  14. Pattern: Singleton [I] Speichert die Instanz Privater Konstruktor Erzeugt Instanz oder gibt sie zurück • Die Methode “getInstance“ liefert die eine Instanz der Klasse zurück • Ein privater Konstruktor verbietet das externe Instanzieren der Klasse • instance speichert die eine Instanz der Klasse als statisches Attribut

  15. Pattern: Singleton [II] void someFunction() { Berufsakademie.getInstance().addSemester( … ); }

  16. Das Template Method-Pattern

  17. Benotung von Studenten I • klausurenKorrigieren definiert einen festen Algorithmus: • Musterlösung bereitstellen • Die Klausuren aller Studenten mit der Musterlösung vergleichen • Dem Studiengangsleiter die Ergebnisse mitteilen • Verschiedene Dozenten benoten Studenten unterschiedlich • Fair • Unfair • Alle kommen durch • Zufällig if( fairness == ‘fair‘ ) { … } else if( fairness == ‘unfair‘ ) { } … fairness = { ‘fair‘, ‘unfair‘, ‘allekommendurch‘, ‘zufällig‘};

  18. Problem dieses Ansatzes: Stets, wenn ein neuer Dozententyp erscheint, muss die Klasse BADozent angepasst werden Die Methode klausurenKorrigieren wird unübersichtlich und unwartbar Benotung von Studenten II

  19. Codestellen isolieren, die sich häufig ändern können und flexibel für Änderungen zu machen Trennung von statischen und dynamischen Programmstellen Design Prizipien I

  20. Pattern: Template Method • Es werden Subklassen gebildet, die den variierenden Teil spezifisch implementieren • Alles Statische bleibt in der Superklasse, der variable Algorithmus wird der Subklasse überlassen

  21. Template Method II • Die Methode benote wird abstrakt, jede Subklasse muss diese Implementieren • Das Grundgerüst des Algorithmus klausurenKorrigieren wird von der Klasse BADozent bereitgestellt (Musterlösung bereitstellen, alle Studenten benoten, Studiengangsleiter benachrichtigen)

  22. Nun können alle Subklassen ihre eigene Implementierung realisieren Template Method III class ZufälligeNotenDozent extends BADozent { protected void benote( BAStudent st ) { st.setNote( Math.Random() * 5 + 1 ); } } class UnfairerDozent extends BADozent { protected void benote( BAStudent st ) { st.setNote( Math.Random() * 2 + 4 ); } } class FairerDozent extends BADozent { protected void benote( BAStudent st ) { st.setNote( Math.Random() * 5 + 1 ); } } class AlleKommenDurchDozent extends BADozent { protected void benote( BAStudent st ) { st.setNote( Math.Random() * 3 + 1 ); } }

  23. Was, wenn manche Dozenten während der Korrektur die Lust verlieren und deshalb zu Beginn fairer korrigieren als gegen Ende? (Bspw. ab 50% der Studenten) Der Dozent weiß aktuell nicht, wieviele Studenten noch kommen Lustlos?

  24. Hooks sind Methoden in der Basisklasse, die nicht abstrakt sind, sondern einen leeren Methoden-Body besitzen Bei Bedarf kann eine Subklasse den Hook überschreiben, es ist ihr jedoch frei gestellt Hooks I

  25. Hooks II • BADozent wird um die Methoden korrekturStart und korrekturEnde erweitert • Jeder beliebige Dozenten-Typ kann nun herausfinden, wieviele Studenten er korrigieren wird und so seine Bewertung durchführen Ist nicht daran interessiert, wieviele Studenten folgen Benotung abh. von Anzahl

  26. Das Factory Method-Pattern

  27. Wer erstellt all diese Objekte? • Viele Subklassen machen die Verwaltung schwierig • Problem: Klassen werden an vielen Stellen des Codes erzeugt • Verlust der Übersicht • Es entstehen Abhängigkeiten zwischen vielen Klassen • Bei Parametern im Konstruktor: Anpassung des Konstruktors verherend • Unwartbarer Code! new FairerDozent(…) new UnfairerDozent(…) new FairerDozent(…) new AlleKommenDurchDozent(…) new UnfairerDozent(…)

  28. So nicht! Jeder kennt jeden! So verursacht die geringste Änderung ein Dilemma.

  29. Wenn möchlich nicht gegen konkrete Implementierungen sondern gegen Interfaces und abstrakte Klassen programmieren! Design Prizipien II LaunischerDozent infoDozent; … infoDozent = new LaunischerDozent(); infoDozent.klausuren…( … ); statt BADozent infoDozent; … infoDozent = new ???(); infoDozent.klausuren…( … ); besser

  30. Design Prizipien III • Annahme: Die Art des Dozenten hängt von Fach, Geschlecht und Alter ab • Statt hier eine Unterscheidung zu machen, verwenden wir eine Klasse, die uns die Instanzen erzeugt BADozent infoDozent; … infoDozent = new ???(); infoDozent.klausuren…( … ); besser

  31. Die Factory regelt das • Die Fakultäten kennen die Factory und die abstrakte Klasse BADozent, die Factory kennt alle Dozenten-Typen • Änderungen an den Dozenten-Typen müssen nur an der Factory gewartet werden

  32. CreateDozent BADozent createDozent( int age, String subject, String gender ) { if( age > 65 ) { return new AlleKommenDurchDozent(); } if( subject.equals( “DB“ ) && gender.equals( “male“ ) ) { return new UnfairerDozent(); } if( subject.equals( “BWL“ ) ) { return new ZufälligeNotenDozent(); } return new FairerDozent(); }

  33. Was, wenn Dozenten verschiedener Fakultäten unterschiedliche Gewichtungen bei der Charakterbildung der Dozenten haben? Bsp: Informatik: Fair = {<40, weiblich, nicht Datenbanken} Maschinenbau: Fair = {>60, männlich, alle technischen Fächer} Und die Fakultäten?

  34. Jede Fakultät verwendet ihre eigene Factory, die nach ihrem spezifischem Algorithmus die Dozenten klassifiziert Die Klasse DozentFactory ist nun abstrakt und zwingt die Subklassen, die Methode zu implementieren Pattern: Factory-Method

  35. Wieder wurden die variablen Teile von den statischen getrennt Die Factory-Methode ist eine spezielle Template-Methode Erkannt? Potentiell variabel

  36. Das State-Pattern

  37. Zustände I

  38. Zustände II • 5 Zustände • Keine Klausur geschrieben • Klausur nicht best. • Nachklausur nicht best. • Fach best. • Fach nicht best. • 3 Transitionen • durchgefallen • bestanden • krank am Klausurtag

  39. Ansatz: Zustandsattribut class BAStudent { private final static int KEINE_KLAUSUR_GESCHR = 0; private final static int KLAUSUR_NICHT = 1; private final static int NACHKLAUSUR_NICHT = 2; private final static int BESTANDEN = 3; private final static int NICHT_BESTANDEN = 4; private int state = BAStudent.KEINE_KLAUSUR_GESCHR; public void durchgefallen() {…} public void bestanden() {…} public void krank() {…} }

  40. Methoden public void durchgefallen() { switch( state ) { case KEINE_KLAUSUR_GESCHR: state = KLAUSUR_NICHT; break; case KLAUSUR_NICHT: state = NACHKLAUSUR_NICHT; break; case NACHKLAUSUR_NICHT: state = NICHT_BESTANDEN; break; default: throw new Exception( “Nicht erlaubt!“ ); } } public void bestanden() { … } public void krank() { if( state… ) { … } }

  41. Design Prinzipien? public void durchgefallen() { switch( state ) { case KEINE_KLAUSUR_GESCHR: state = KLAUSUR_NICHT; break; case KLAUSUR_NICHT: state = NACHKLAUSUR_NICHT; break; case NACHKLAUSUR_NICHT: state = NICHT_BESTANDEN; break; default: throw new Exception( “Nicht erlaubt!“ ); } } • Keine Abkapselung der Programm-Teile, die variieren können • Zustandsübergänge sind nicht explizit sondern inmitten der Contitional Statements vergraben • Code ist Fehler-anfällig: ein neuer Zustand muss in allen Methoden gepflegt, kann jedoch übersehen werden • Nicht objektorientiert

  42. State Pattern I • Interface State, definiert die Transitionsmethoden • Für jeden möglichen Zustand existiert eine Subklasse von State • BestandenState • NachklausurNichtState • DurchgefallenState • KlausurNichtState • KeineKlausurState • Die Klasse BAStudent delegiert den Methodenaufruf lediglich an das State-Objekt

  43. State Pattern II • Alle State-Objekte haben eine Referenz auf das BAStudent-Objekt • Durch die Methode setState können die Zustände Transitionen auslösen

  44. State Pattern III class KeineKlausurState implements State { BAStudent student; public KeineKlausurState( BAStudent student ) { this.student = student; //jeder State bekommt eine Referenz des Studenten injiziert } public void durchgefallen() { this.student.setState( … ); } public void bestanden() { this.student.setState( … ); } public void krank() { // der Zustand wird nicht geändert } } Zustands-transitionen

  45. State Pattern IV class KeineKlausurState implements State { BAStudent student; public KeineKlausurState( BAStudent student ) { this.student = student; //jeder State bekommt eine Referenz des Studenten injiziert } public void durchgefallen() { this.student.setState( … ); } public void bestanden() { this.student.setState( … ); } public void krank() { // der Zustand wird nicht geändert } } Zustands-transitionen

  46. State Pattern V class KeineKlausurState implements State { BAStudent student; public KeineKlausurState( BAStudent student ) { this.student = student; //jeder State bekommt eine Referenz des Studenten injiziert } public void durchgefallen() { this.student.setState( … ); } public void bestanden() { this.student.setState( … ); } public void krank() { // der Zustand wird nicht geändert } } Zustands-transitionen Die Klasse BAStudent hält alle möglichen Zustände vor

  47. State Pattern VI class KeineKlausurState implements State { BAStudent student; public KeineKlausurState( BAStudent student ) { this.student = student; //jeder State bekommt eine Referenz des Studenten injiziert } public void durchgefallen() { this.student.setState( this.student.GetKlausurNichtState() ); } public void bestanden() { this.student.setState( this.student.GetBestandenState() ); } public void krank() { // der Zustand wird nicht geändert } }

  48. Es gibt neben den hier vorgestellten noch viele nützliche Patterns Patterns werden in der Software-Entwicklung gerne und häufig eingesetzt Beispiel: Java SDK API Factory Method: BorderFactory Observer Pattern: Event-Listener … Weitere Patterns?

More Related