Pobieranie prezentacji. Proszę czekać

Pobieranie prezentacji. Proszę czekać

Wzorce projektowe w C# WWW: Jacek Matulewski Instytut Fizyki, UMK WWW:

Podobne prezentacje


Prezentacja na temat: "Wzorce projektowe w C# WWW: Jacek Matulewski Instytut Fizyki, UMK WWW:"— Zapis prezentacji:

1 Wzorce projektowe w C# WWW: Jacek Matulewski Instytut Fizyki, UMK WWW: semestr letni 2016

2 Główna lektura 1 Głównym materiałem źródłowym jest książka tzw. gangu czworga pt. „Wzorce projektowe”.

3 Główna lektura 1 Głównym materiałem źródłowym jest książka tzw. gangu czworga pt. „Wzorce projektowe”.

4 Główna lektura 2 Dodatkowo wykorzystamy adaptacje do C# wzorców G4 opisane w książce S. J. Metskera

5 Warunki zaliczenia 1.Warunek konieczny: Odrobienie zadań domowych (może być w parach). 2.Kolokwium (ocena) 3.Ocenę można dodatkowo podnieść biorąc udział w konkursach (zwykle nagroda to +1/2 do oceny). Zadania: Konkursy – w prezentacji

6 Programowanie obiektowe Zagadnienia na powtórzeniu: klasy, pola, metody, własności, zakres dostępności (prywatny, publiczny, chroniony) dziedziczenie, klasy abstrakcyjne (figury), nadpisywanie metod przykład: równanie kwadratowe (double, Complex) testy jednostkowe, refactoring, TDD biblioteki DLL

7 Interfejs (ang. interface) C++: interfejs = klasa abstrakcyjna (ale tylko metody czysto wirtualne) class IFigura { public: virtual double ObliczPole() = 0; virtual double ObliczObwod() = 0; }; class Prostokat : public IFigura { private: double a, b; public: Prostokat(double a, double b) { this->a = a; this->b = b; } double ObliczPole() { return a * b; } double ObliczObwod() { return 2 * a + 2 * b; } };

8 Interfejs (ang. interface) C++: interfejs = klasa abstrakcyjna (ale tylko metody czysto wirtualne) Prostokat prostokat(2, 3); std::cout << "Pole: " << prostokat.ObliczPole() << "\n"; std::cout << "Obwod: " << prostokat.ObliczObwod() << "\n"; std::cout << "\n"; Prostokat* pprostokat = new Prostokat(2, 3); std::cout ObliczPole() << "\n"; std::cout ObliczObwod() << "\n"; std::cout << "\n"; IFigura* pfigura = new Prostokat(2, 3); std::cout ObliczPole() << "\n"; std::cout ObliczObwod() << "\n"; std::cout << "\n";

9 Interfejs (ang. interface) C#: można nadal używać klas abstrakcyjnych w roli interfejsów public abstract class Figura { public abstract double ObliczPole(); public abstract double ObliczObwód(); } class Prostokąt : Figura { private double a, b; public Prostokąt(double a, double b) { this.a = a; this.b = b; } public override double ObliczPole() { return a * b; } public override double ObliczObwód() { return 2 * a + 2 * b; } };

10 Interfejs (ang. interface) C#: można nadal używać klas abstrakcyjnych w roli interfejsów Prostokąt prostokąt = new Prostokąt(2, 3); Console.WriteLine("Pole: " + prostokąt.ObliczPole()); Console.WriteLine("Obwod: " + prostokąt.ObliczObwód()); Console.WriteLine(); Figura figura = new Prostokąt(2, 3); Console.WriteLine("Pole: " + figura.ObliczPole()); Console.WriteLine("Obwod: " + figura.ObliczObwód()); Console.WriteLine();

11 Interfejs (ang. interface) C#: specjalna konstrukcja pozwalająca na definiowanie interfejsów (słowo kluczowe interface) public interface IFigura { double ObliczPole(); double ObliczObwód(); } class Prostokąt : IFigura { private double a, b; public Prostokąt(double a, double b) { this.a = a; this.b = b; } public override double ObliczPole() { return a * b; } public override double ObliczObwód() { return 2 * a + 2 * b; } };

12 Interfejs (ang. interface) C#: specjalna konstrukcja pozwalająca na definiowanie interfejsów (słowo kluczowe interface) Prostokąt prostokąt = new Prostokąt(2, 3); Console.WriteLine("Pole: " + prostokąt.ObliczPole()); Console.WriteLine("Obwod: " + prostokąt.ObliczObwód()); Console.WriteLine(); IFigura figura = new Prostokąt(2, 3); Console.WriteLine("Pole: " + figura.ObliczPole()); Console.WriteLine("Obwod: " + figura.ObliczObwód()); Console.WriteLine();

13 Interfejs (ang. interface) C#: specjalna konstrukcja pozwalająca na definiowanie interfejsów (słowo kluczowe interface) public interface IFigura { double Pole { get; } //własności double Obwód { get; } } class Prostokąt : IFigura { private double a, b; public Prostokąt(double a, double b) { this.a = a; this.b = b; } public double Pole { get { return a * b; } } public double Obwód { get { return 2 * a + 2 * b; } } };

14 Interfejs (ang. interface) C#: specjalna konstrukcja pozwalająca na definiowanie interfejsów (słowo kluczowe interface) Prostokąt prostokąt = new Prostokąt(2, 3); Console.WriteLine("Pole: " + prostokąt.Pole); Console.WriteLine("Obwod: " + prostokąt.Obwód); Console.WriteLine(); IFigura figura = new Prostokąt(2, 3); Console.WriteLine("Pole: " + figura.Pole); Console.WriteLine("Obwod: " + figura.Obwód); Console.WriteLine();

15 Interfejs (ang. interface) Interfejs vs klasa abstrakcyjna Interfejs można zastąpić klasą abstrakcyjną, w której są tylko metody abstrakcyjne Interfejs vs delegacja (typ wskaźnika do metody) Delegacja to typ metody = wymaganie metody lub klasy względem używającego ją kodu Interfejs określa sygnatury metod, w tym i ich nazwy = kontrakt klasy dostarczającej Rola interfejsów: Ograniczenie (rozluźnienie) związków między klasami. Ustalenie kontraktów między nimi. Jednocześnie prowadzi jednak do uwolnienia ich rozwoju, o ile przestrzegamy kontraktu.

16 Użycie interfejsów - zasady SOLID Spopularyzował: Robert C. Martin (uncle Bob) (jeden z sygnatariuszy Agile Manifesto) Cel: przygotowanie kodu, który jest łatwy do utrzymania (konserwacji), rozbudowy i prawd. zmian wymagań

17 Zasady SOLID S. Zasada jednej odpowiedzialności Single responsibility principle (SRP) O. Zasada otwarte-zamknięte Open/close principle (OCP) L. Zasada podstawienia Liskov Liskov substitution principle (LSP) I. Zasada segregacji interfejsów Interface segregation principle (ISP) D. Zasada odwrócenia zależności Dependency inversion principle (DIP)

18 Zasady SOLID Zasada jednej odpowiedzialności (klasy, metody, DLL) Single responsibility principle Boska klasa, którą należy rozdzielić na wiele klas odpowiedzialnych tylko za pojedyncze funkcjonalności Inne sformułowanie: KISS Keep it simple, Stupid! Zmiana jednej funkcjonalności pociąga za sobą konieczność zmiany wielu innych (wszystko splątane)

19 Zasady SOLID Zasada jednej odpowiedzialności (klasy, metody, DLL) Single responsibility principle Przykład dla klas implementujących figury (np. Prostokąt ): Odpowiedzialności: -przechowywanie rozmiaru do obliczeń P i O ( double ), -przechowywanie położenia do rysowania ( int ), -obliczenia pola i obwodu, -rysowanie z System.Drawing.Graphics. Zmiana sposobu rysowania (np. WinForms -> WPF) oznacza konieczność zmiany tej klasy i klas zależnych

20 Zasady SOLID Zasada jednej odpowiedzialności (klasy, metody, DLL) Single responsibility principle public interface IFigura //tu wymieszana odpowiedzialność modelu i widoku { double Pole { get; } double Obwód { get; } void Rysuj(Graphics g, Color kolor, double skala = 1, bool wypełnij = false); } public class Prostokąt : IFigura { private int x, y; private double a, b; public Prostokąt(int x, int y, double a, double b) {... } public double Pole { get { return a * b; } } public double Obwód { get { return 2 * a + 2 * b; } } public void Rysuj(Graphics g, Color kolor, double skala = 1,...) {... } }

21 Zasady SOLID Zasada jednej odpowiedzialności (klasy, metody, DLL) Single responsibility principle Zmiana: -przygotowanie klasy odpowiedzialnej za obliczenia, -przeniesienie kodu odpowiedzialnego za rysowanie do osobnej klasy lub do statycznego „pomocnika” Efekt: rozdzielenie warstw modelu i widoku Zmiana sposobu rysowania dotknie tylko klasy widoku (stosowanie zasady SRP nie musi prowadzić do tworzenia warstw, ale warstwy są efektem konsekwentnego stosowania SRP)

22 Zasady SOLID Zasada jednej odpowiedzialności (klasy, metody, DLL) Single responsibility principle public interface IFigura { double Pole { get; } double Obwód { get; } void Rysuj(Graphics g, Color kolor, double skala = 1, bool wypełnij = false); } public class Prostokąt : IFigura { private int x, y; private double a, b; public Prostokąt(int x, int y, double a, double b) {... } public double Pole { get { return a * b; } } public double Obwód { get { return 2 * a + 2 * b; } } public void Rysuj(Graphics g, Color kolor, double skala = 1,...) {... } }

23 Zasady SOLID Zasada jednej odpowiedzialności (klasy, metody, DLL) Single responsibility principle public static class PomocnikRysowania //helper { public static void Rysuj(this Model.Prostokąt prostokąt, int x, int y, Graphics g, Color kolor, double skala = 1, bool wypełnij = false) { int w = (int)(skala * prostokąt.A); int h = (int)(skala * prostokąt.B); if (!wypełnij) g.DrawRectangle(new Pen(kolor), x, y, w, h); else g.FillRectangle(new SolidBrush(kolor), x, y, w, h); } public static void Rysuj(this Model.IFigura figura, int x, int y, Graphics g, Color kolor, double skala = 1, bool wypełnij = false) {... }

24 Zasady SOLID Zasada otwarte-zamknięte Open/close principle Klasy są otwarte na rozszerzenia, ale zamknięte na modyfikacje To dotyczy też metod/funkcji oraz modułów, czy bibliotek. Idea kodu produkcyjnego, który nie może być zmieniany (poza naprawianiem błędów) „Do dodania możliwości założenia kapelusza nie powinna być potrzebna operacja mózgu!”

25 Zasady SOLID Zasada otwarte-zamknięte Open/close principle Rozwiązania tego pozornego paradoksu: -wprowadzenie abstrakcji umożliwiających „podmianę” kodu na inny bez modyfikacji zasadniczej klasy (interfejsy, „wstrzykiwanie” kodu), -dodanie lub zmiana funkcjonalności w klasie potomnej. Zasada OCP wymaga projektowania kodu w sposób ułatwiający jego późniejszą rozbudowę

26 Zasady SOLID Zasada otwarte-zamknięte Open/close principle Przykład: -klasy reprezentujące prostokąt i okrąg -Statyczny pomocnik obliczający pola poszczególnych figur (za obliczanie pól w pełni odpowiedzialny jest pomocnik) Problem (jak zwykle w przypadku SOLID): Jak napisać kod w taki sposób, żeby był łatwy do rozbudowy?

27 Zasady SOLID Zasada otwarte-zamknięte Open/close principle public class Prostokąt { public double A { get; private set; } public double B { get; private set; } public Prostokąt(double a, double b) { A = a; B = b; } } public class Okrąg { public double R{ get; private set; } public Okrąg(double r) { R = r; } }

28 Zasady SOLID Zasada otwarte-zamknięte Open/close principle public static class SumatorPólFigur { public static double SumujPolaFigur(object[] figury) { double sumaPól = 0; foreach(object figura in figury) { if(figura is Prostokąt) { Prostokąt prostokąt = figura as Prostokąt; sumaPól += prostokąt.A * prostokąt.B; }... } return sumaPól; } Klient: rozszerzyć zbiór figur o nowe Dodajemy kolejny if i polecenia zależ. Ukryta zależność od klas Prostokąt, …

29 Zasady SOLID Zasada otwarte-zamknięte Open/close principle public interface IFigura { double Pole { get; } } public class Prostokąt : IFigura { public double A { get; private set; } public double B { get; private set; } public Prostokąt(double a, double b) { A = a; B = b; } public double Pole { get { return a * b; } } } Klasy figur przejmują odpowiedzialność za obliczanie figur Interfejs = abstrakcja

30 Zasady SOLID Zasada otwarte-zamknięte Open/close principle public static class SumatorPólFigur { public static double SumujPolaFigur(IFigura[] figury) { double sumaPól = 0; foreach(IFigura figura in figury) { sumaPól += figura.Pole; } return sumaPól; } Klient: rozszerzyć zbiór figur o nowe Dodajemy nową klasę impl. IFigura Bez instrukcji warunkowych

31 Zasady SOLID Zasada podstawiania Liskov Liskov subsitution principle Funkcje które używają wskaźników lub referencji do klas bazowych, muszą być w stanie używać również obiektów klas dziedziczących po klasach bazowych, bez dokładnej znajomości tych obiektów. Idea standaryzacji: baterie AA = R6, AAA = R03, … Interfejsy jako specyfikacje standardów

32 Zasady SOLID Zasada podstawiania Liskov Liskov subsitution principle Z zasady LSP wynika, że klasa potomna powinna rozszerzać funkcjonalność klasy bazowej, a nie ją zawężać lub całkowicie zmieniać. Sposób użycia klasy potomnej powinien być taki sam, jak klasy bazowej. Pełna wymienność klas potomnych, ale również klasa bazowa powinna móc zastąpić klasę potomną

33 Zasady SOLID Zasada podstawiania Liskov Liskov subsitution principle public class Prostokąt { protected double a = 0, b = 0; public virtual double A { get { return a; } set { a = value; } } public virtual double B { get { return b; } set { b = value; } } public double Pole { get { return a * b; } } } public class Kwadrat : Prostokąt //ta klasa nie rozszerza klasy bazowej { public override double A { get { return a; } set { a = value; b = value; } } public override double B { get { return b; } set { a = value; b = value; } } }

34 Zasady SOLID Zasada podstawiania Liskov Liskov subsitution principle public static double ZmieńBokiIObliczPole(Prostokąt prostokąt, double a, b) { prostokąt.A = a; prostokąt.B = b; return prostokąt.Pole; } Wynik wywołania: Pole (prostokąt): 6, pole (kwadrat): 9 Spodziewamy się, że instancja klasy potomnej może być przesłana z równym skutkiem, jak instancja klasy bazowej.

35 Zasady SOLID Zasada podstawiania Liskov Liskov subsitution principle public interface IFigura { double Pole { get; } } public class Prostokąt : IFigura { protected double a = 0, b = 0; public virtual double A { get { return a; } set { a = value; } } public virtual double B { get { return b; } set { b = value; } } public double Pole { get { return a * b; } } } public class Kwadrat : IFigura //Klasa Kwadrat nie dziedziczy po Prostokąt { public override double A { get { return a; } set { a = value; b = value; } } public override double B { get { return b; } set { a = value; b = value; } } public double Pole { get { return a * a; } } }

36 Zasady SOLID Zasada segregacji interfejsów Interface segregation principle Redukcja zależności między klasami: związki między klasami powinny być ograniczone do minimum, czyli klient klasy powinien mieć dostęp tylko do tych składowych, których rzeczywiście potrzebuje Klasa: Prostokąt Klasa-klient: KalkulatorPola, KalkulatorObwodu

37 Zasady SOLID Zasada segregacji interfejsów Interface segregation principle Po co? Co się stanie w przypadku zmiany klasy Prostokąt lub klas-klientów? Jak ograniczyć zmiany w całym kodzie? Kontrakty między klasami = interface’y Klasa: Prostokąt Klasa-klient: KalkulatorPola, KalkulatorObwodu

38 Zasady SOLID Zasada segregacji interfejsów Interface segregation principle public interface IFigura { double Pole { get; } double Obwód { get; } } public class Prostokąt : IFigura { protected double a = 0, b = 0; public Prostokąt(double a, double b) { this.a = a; this.b = b; } public double Pole { get { return a * b; } } public double Obwód { get { return 2 * a + 2 * b; } } }

39 Zasady SOLID Zasada segregacji interfejsów Interface segregation principle //klasa SumatorPólFigur public static double ObliczSumęPól(IEnumerable figury) { double sumaPól = 0; foreach (IFigura figura in figury) sumaPól += figura.Pole; return sumaPól; } //klasa SumatorObwodówFigur public static double ObliczSumęObwodów(IEnumerable figury) { double sumaObwodów = 0; foreach (IFigura figura in figury) sumaObwodów += figura.Obwód; return sumaObwodów; }

40 Zasady SOLID Zasada segregacji interfejsów Interface segregation principle Osobne interfejsy na poszczególne funkcjonalności (kontrakty z klientami ograniczają zakres zmian): public interface IFiguraZPolem { double Pole { get; } } public interface IFiguraZObwodem { double Obwód { get; } } public class Prostokąt : IFiguraZPolem, IFiguraZObwodem { protected double a = 0, b = 0; public Prostokąt(double a, double b) { this.a = a; this.b = b; } public double Pole { get { return a * b; } } public double Obwód { get { return 2 * a + 2 * b; } } }

41 Zasady SOLID Zasada segregacji interfejsów Interface segregation principle //klasa SumatorPólFigur public static double ObliczSumęPól(IEnumerable figury) { double sumaPól = 0; foreach (IFiguraZPolem figura in figury) sumaPól += figura.Pole; return sumaPól; } //klasa SumatorObwodówFigur public static double ObliczSumęObwodów(IEnumerable figury) { double sumaObwodów = 0; foreach (IFiguraZObwodem figura in figury) sumaObwodów += figura.Obwód; return sumaObwodów; }

42 Zasady SOLID Zasada odwrócenia zależności Dependency inversion principle Oczywista oczywistość: Niższe warstwy architektoniczne nie mogą zależeć od wyższych! DIP: Zależność wyższych warstw od niższych też powinna być ograniczona jedynie do kontaktów (interfejsów) W przypadku zmian w module takie osłabienie wiązania ogranicza zakres koniecznych zmian w innych modułach. Zapewnia wymienność modułów z niższej warstwy.

43 Zasady SOLID Zasada odwrócenia zależności Dependency inversion principle //niższa warstwa public class Prostokąt { private double a, b; public Prostokąt(double a, double b) { this.a = a; this.b = b; } public double Pole { get { return a * b; } } } //wyższa warstwa (klasa silnie zależna od klasy Prostokąt) public class Opakowanie { private Prostokąt prostokąt = null; public Opakowanie(double a, double b) { prostokąt = new Prostokąt(a, b); } public double ObliczPole() { return prostokąt.Pole; } }

44 Zasady SOLID Zasada odwrócenia zależności Dependency inversion principle Silna zależność klasy Opakowanie od klasy Prostokąt: nie można wymienić klasy podrzędnej na inną w razie zmian w którejkolwiek z klasy, druga musi także być modyfikowana Zasada DIP: Moduły z wyższej warstwy nie powinny zależeć od modułów z niższej warstwy. Oba powinny zależeć od abstrakcji (np. interfejsu) Abstrakcja nie powinna zależeć od szczegółów (np. a, b), to szczegóły powinny zależeć od abstrakcji (nie ma ich w interf.)

45 Zasady SOLID Zasada odwrócenia zależności Dependency inversion principle public interface IFiguraZPolem { double Pole { get; } } //abstrakcja //niższa warstwa (zależy od abstrakcji) public class Prostokąt : IFigura { private double a, b; public Prostokąt(double a, double b) { this.a = a; this.b = b; } public double Pole { get { return a * b; } } } //wyższa warstwa (metoda zależy tylko od abstrakcji) public class Opakowanie { private IFiguraZPolem figura = null; public Opakowanie(IFiguraZPolem figura) {this.figura = figura; } public double ObliczPole() { return figura.Pole; } }

46 Zasady SOLID Zasada odwrócenia zależności Dependency inversion principle W przypadku zmian w module takie osłabienie wiązania ogranicza zakres koniecznych zmian w innych modułach. Zapewnia wymienność modułów z niższej warstwy. Rozwiązanie, które zastosowaliśmy to Dependency Injection (wstrzyknięcie zależności). Można wstrzyknąć obiekt przez konstruktor, własność lub do jednej konkretnej metody, która używa zależności. Uwaga! W ogólności DI ≠ IoC ≠ DIP (DI ϵ IoC ϵ DIP)

47 Zasady SOLID Zasady SOLID  usuwanie zależności między klasami  ogólność (wymienność klas) i podatność na zmiany Dependency Inversion Principle (DIP) – osłabianie (decoupling) zależności klas z wyższych warstw od klas z niższych Design by Contract (programowanie poprzez kontakt) – metodyka tworzenie systemów, w których kładzie się nacisk na zasady SOLID Inversion of Control (IoC, odwrócenie sterowania) – przenoszenie części odpowiedzialności poza klasę np. klient tworzący klasę Opakowanie ma kontrolę nad sposobem obliczania figury (może przekazać taką implementację interfejsu IFiguraZPolem jaką zechce, dowolnie obliczającą pole figury). Dependency Injection (wstrzykiw. zależności) – jedna z realizacji IoC

48 Zasady GRASP General Responsibility Assignment Software Principles zasady mówiące o podziale odpowiedzialności w systemie komp. Zasady zebrane przez Craiga Larmana w książce Wzorce GoF można traktować jako konsekwencję stosowania zasad GRASP Przykład skróconego opisu: Ekspert (Information Expert) Pytanie: Której klasie przypisać odpowiedzialność/zadanie? Odpowiedź: Tej, która ma niezbędne informacje (aby uniknąć przekazywania danych i związanych z tym powiązań między klasami)

49 Zasady GRASP General Responsibility Assignment Software Principles zasady mówiące o podziale odpowiedzialności w systemie komp. Twórca (Creator) Pytanie: Która klasa powinna tworzyć obiekt jakiejś klasy Klasa ? Odpowiedź: Ta klasa, która: -przechowuje kolekcje klas Klasa, -jest mocno powiązana z klasą Klasa, -ma dane niezbędne do inicjacji instancji Klasa. Im więcej przesłanek, tym lepsza decyzja.

50 Zasady GRASP General Responsibility Assignment Software Principles zasady mówiące o podziale odpowiedzialności w systemie komp. Kontroler (Controller) Pytanie: Jaki obiekt (z warstwy modelu) powinien obsługiwać żądania użytkownika (np. przesyłane z warstwy widoku / GUI)? Odpowiedź: klasa kontrolera powinna: -opisywać działanie systemu jako całości (spinać go), -reprezentować urządzenie, na którym działa system, -reprezentować przypadek użycia ( Generalnie: powinna to być klasa, która organizuje pracę systemu.

51 Zasady GRASP General Responsibility Assignment Software Principles zasady mówiące o podziale odpowiedzialności w systemie komp. Niska liczba powiązań (Low Coupling) Wysoka spójność (High Cohesion) Pytanie: Jak zmniejszyć powiązania między klasami systemu? Jak nie przeciążać klasę obowiązkami? Odpowiedź: Każda klasa powinna mieć tylko jedno zadanie (jedną odpowiedzialność), ale na tyle obszerne, żeby nie wymagało współpracy z innymi klasami (unikanie powiązań między klasami). Porównaj z: Single Responsibility Principle i boskie klasy

52 Zasady GRASP General Responsibility Assignment Software Principles zasady mówiące o podziale odpowiedzialności w systemie komp. Pośrednictwo (Indirection) Pytanie: Jak ograniczyć powiązania między dwoma pakietami klas? Odpowiedź: Wstawić między te pakiety dodatkową klasę, która przejmie odpowiedzialność za komunikację i tłumaczenie danych, wywołania metod przekazywanych między obydwoma pakietami To sprzyja zasadom Niskiej liczby powiązań i Wysokiej spójności Przykład: Warstwa dostępowa (DAL) między bazą danych i BLL Efekt: BLL nie zależy od sposobu zapisywania danych

53 Zasady GRASP General Responsibility Assignment Software Principles zasady mówiące o podziale odpowiedzialności w systemie komp. Polimorfizm (Polymorphism) Przejmowanie odpowiedzialności w przypadku alternatywnych możliwości -> alternatywne klasy zgodne z tym samym interfejsem Zapewniona zmienność (Protected Variations) Jak zaprojektować system z łatwo wymienialnymi modułami? Klasy podejrzewane o duże zmiany w przyszłości (niestabilne) zapośredniczyć interfejsami – łatwo będzie je wymienić na inne Czysty wymysł (Pure Fabrication) Wyjście awaryjne, gdy pozostałe zasady dają sprzeczne zalecenia Klasa (np. singleton) realizująca jedynie usługi na rzecz innych klas

54 Dodatek: Agile Manifesto Odkrywamy nowe metody programowania dzięki praktyce w programowaniu i wspieraniu w nim innych. W wyniku naszej pracy, zaczęliśmy bardziej cenić: ludzi i interakcje od procesów i narzędzi działające oprogramowanie od szczegółowej dokumentacji współpracę z klientem od negocjacji umów, reagowanie na zmiany od realizacji założonego planu. Oznacza to, że elementy wypisane po prawej są wartościowe, ale większą wartość mają dla nas te, które wypisano po lewej. JM: To że jesteśmy zwinni i chętni do zmian, nie oznacza, że nie każemy sobie płacić za dodatkowe godziny spędzone nad kodem.

55

56 SCRUM Scrum Guide (ok. 20 stron, także po polsku) Ken Schwaber i Jeff Sutherland Ken Schwaber Uwaga! Słabe tłumaczenie

57 SCRUM Tradycyjne metodologie wytwarzania oprogramowania dążą do szczegółowej kontroli całego procesu, w tym kontroli przydzielania zadań członkom zespołu oraz długoterminowego planowania prac, a następnie skrupulatnego rozliczania z postępów realizacji planu (por. kontrola lotów samolotów, odpowiedzialni są kontrolerzy r. l.) Załamanie scentralizowanej kontroli i systemu przydziału zadań wraz ze wzrostem złożoności projektów informatycznych Scrum (jedna z metodologii zwinnych, agile) – zaufanie do zespołu, skrócenie okresów produkcji do sprintów (krótsza perspektywa), plan zastąpiony przez zaległości produktowe (backlog, spis zadań), zaangażowanie klienta – częste wydania z nowymi funkcjonalnościmi (por. proste zasady ruchu drogowego, odpowiedzialny jest kierowca)

58 SCRUM Empiryczna kontrola procesu wytwarzania oprogramowania sposób na poradzenie sobie ze złożonością  nieprzewidywalnością Widoczność – projekt jest przejrzysty dla kierownictwa i dla klienta. Żadne problemy nie są ukrywane, jasne kryterium „zakończone”. Inspekcja – częsta kontrola wszystkich aspektów rozwijanego oprogramowania i samego procesu (np. przeglądy jakości kodu) Adaptacja – natychmiastowe wdrożenie zaleceń inspektora, aktualizowanie priorytetów przed każdym sprintem (przebiegiem) W SCRUM nie ma etapu szczegółowej analizy, przygotowywania SRS. Już do pierwszego przebiegu z klientem wybierana jest konkretna funkcjonalność, która powinna zostać zaimplementowana po msc.

59 SCRUM Struktura SCRUM = przyrostowe iteracje Zaległości produktu wybrane do implementacji w danej iteracji Sprint (przebieg, iteracja) od 2 tyg. do miesiąca Codzienne spotkania na stojąco (daily scrum) Ich cel to zabranie się do pracy, a nie myślenie o pracy Przyrost funkcjonalności produktu (możliwy do wdrożenia) Dziennik Zaległości (sortowany według aktual. priorytetów)

60 SCRUM SCRUM to iteracyjna metoda przyrostowa wytwarzania oprogramowania Reguły SCRUM: 1. reguła sashimi – każdy przyrost będący efektem pracy zespołu podczas sprintu musi być w pełni ukończony (def. „zrobione”), co obejmuje analizy, dokumentację, testy, itd. dla tego fragmentu produktu. - Tylko działające oprogramowanie (produkt) jest miarą postępu projektu. - Klient ocenia przydatność (do jego celów biznesowych) kolejnych, w pełni funkcjonalnych wydań produktu. - Jeżeli przyrost nieukończony, to braki wpisywane są do zaległości.

61 SCRUM Dziennik zaległości (backlog) jest stale sortowany zgodnie z aktualnymi priorytetami klienta. Może być zmieniany. Nie powinno się jednak zmieniać celów aktualnego sprintu (  kryzysowe przerwanie sprintu powinno być sytuacją wyjątkową) Reguły SCRUM: 2. brak zewnętrznego wpływu na przebieg sprintu, samoorganizacja (  skupienie na ustalonej pracy) 3. możliwa zmiana priorytetów zespołu podczas planowania sprintu (  najwyżej dni straty)

62 SCRUM Świnie i kurczaki

63 SCRUM Role w SCRUM (świnie): Właściciel produktu – zadania: - zbiera początkowe i ogólne wymagania, - ustala (nieostateczną) wizję gotowego produktu (zwrot inwestycji) - ustala plan wydań i akceptuje produkt wytworzony w przebiegu, - zarządza dziennikiem zaległości produktowych (w tym sortowaniem zadań zgodnie z aktualnymi priorytetami) Odpowiedzialność za: zwrot kosztów inwestycji produktu – wybór funkcjonalności, które rozwiązują problemy biznesowe klienta (  sortowanie zaległości)

64 SCRUM Role w SCRUM (świnie): Zespół – optymalnie składa się z 5-9 osób - zespół sam ustala cel przebiegu (biorąc pod uwagę priorytety), - autonomicznie rozdziela prace między siebie, - dba o jakość kodu (inspekcje, rewizje), - zmienia zaległości produktowe w nowe funkcjonalności produktu, - pod koniec przebiegu prezentuje efekty właścicielowi produktu Odpowiedzialność: Zespół jest w pełni odpowiedzialny za zarządzanie samym sobą! W zespole nie ma hierarchii lub innej struktury, która utrudniałaby komunikację. To nie znaczy, że nie uznaje się doświadczenia i stażu. Zarządzanie = przeprowadzanie inspekcji (emp. kontr.)  adaptacja

65 SCRUM Role w SCRUM (świnie): Scrum Master – nie jest kierownikiem projektu (project manager) - nie kieruje zespołem – zespół sam się organizuje, - nie sprawdza postępów prac i nie rozdaje dziennych zadań, - zamiast szefa jest raczej trenerem (także właściciela produktu), - pilnuje przestrzegania zasad SCRUM, pomaga wdrażać SCRUM, - dba o warunki pracy, usuwa przeszkody (techniczne i społeczne), zarządza kryzysami i konfliktami, chroni zespół przed utrudnieniami - chroni zespół przed właścicielem produktu i działem marketingu, ale również dba o dobrą komunikację z właścicielem produktu  - dba o otwartość i prawdziwość informacji o postępie prac, informuje wszystkie strony (także kurczaki) o ew. trudnościach, - dba o integrację zespołu

66 SCRUM Role w SCRUM: Właściciel produktuScrum MasterZespół

67 SCRUM Role w SCRUM (świnie): Ken Schwaber: Ważnym zadaniem Scrum Mastera jest dbanie o to, żeby zespół i właściciel produktu skupiali się na tym, co może zostać zrobione, a nie przeżywali frustracji z powodu rzeczy, które aktualnie nie mogą być wykonane. SCRUM to „sztuka rzeczy możliwych”. Ważne jest ograniczenie perspektywy czasowej do 30 dni: - pozwala zespołowi na skupienie się na bieżących zadaniach, ogranicza chaos zadań, krótkoterminowe plany działania, - utrzymuje zainteresowanie udziałowców projektem (widzą efekty i mają wpływ na wybieranie celów kolejnych iteracji)

68 SCRUM Daily scrum – prowadzone przez Scrum Mastera codzienne spotkanie przed rozpoczęciem pracy, nie dłuższe niż kwadrans (mogą być prowadzone na stojąco przy tablicy Kanban) Scrum Master zadaje każdemu członkowi zespołu trzy pytania: 1. Co zrobiłeś od ostatniego codziennego spotkania Scrum? 2. Co zrobisz do następnego spotkania (zobowiązanie)? 3. Co przeszkadza Ci w pracy? Uwaga! To nie oznacza, że Scrum Master: 1. Sprawdza i ocenia postępy prac 2. Przydziela zadania na kolejny dzień 3. Bezpośrednio wspiera zespół w tworzeniu kodu Celem spotkania jest zabranie się do pracy, a nie myślenie o pracy W razie problemów: spotkanie w mniejszych grupach po daily scrum

69 SCRUM Kurczaki – obserwatorzy: Wszystkie osoby zainteresowane sukcesem projektu, w tym: - zarząd firmy, - dział marketingu, - klienci (finansujący projekt), - przyszli użytkownicy produktu. Nie są zaangażowani w wytwarzanie oprogramowania. W trakcie sprintu kontakt z kurczakami poprzez właściciela produktu. Plan sprintu/całego procesu: - Jakich zmian oczekują klienci po zakończeniu sprintu/procesu? - Jakie są postępy po ostatnim sprincie? - Weryfikacja opłacalności inwestycji i wiarygodności zespołu.

70 Tablica Kanban Kanban (jap.) = widoczny spis KANBAN oznacza też metodologię prowadzenia projektów (por. Toyota Management System), w której kładzie się nacisk na ograniczenie bezczynności pracowników i ograniczenie zapasów. https://pl.wikipedia.org/wiki/Tablica_kanban

71 SCRUM Raporty ze sprintów – pełna przejrzystość Wspólna dla świń i kurczaków definicja „zrobione” Po sprincie cztery raporty (mogą być zwykłe arkusze, bez opisów): 1. Lista zaległości produktu sprzed ostatniego sprintu 2. Aktualna lista zaległości produktu (po bieżącym sprincie) 3. Raport zmian (szczegółowa lista różnic 2. – 1.) 4. Wygasający raport zaległości produktowych (może być w postaci wykresu wypalania, burnout chart)

72 SCRUM Przebieg sprintu w SCRUM: 1. Planowanie sprintu 2. Sprint (w tym codzienne spotkania) 3. Przegląd sprintu 4. Retrospekcja

73 SCRUM Przebieg sprintu w SCRUM: 1. Planowanie sprintu – pierwszy dzień cyklu, maksymalnie 8 godz. a. określenie zaległości produktowych (maks. 4 godz.) b. ustalenie zaległości dla najbliższego sprintu (zobowiązanie zesp.) Obecni: właściciel, Scrum Master, zespół, zaproszone kurczaki Efekt: lista zadań do najbliższego sprintu

74 SCRUM Przebieg sprintu w SCRUM: 2. Sprint – maksymalnie 30 dni (minimum dwa tygodnie) - realizacja przez zespół zobowiązań, zakaz ingerencji - codzienne spotkania (tylko zespół i Scrum Master) Efekt: gotowy do wdrożenia produkt z nową funkcjonalnością

75 SCRUM Przebieg sprintu w SCRUM: 3. Przegląd sprintu – ostatni dzień cyklu, maksymalnie 4 godz. - przygotowanie do przeglądu – ok. 1 godz. - prezentacja właścicielowi produktu i kurczakom wykonanej funkcjonalności (prezentowane jest tylko to, co w pełni „zrobione”) - to jest czas na komentarze i krytykę udziałowców (kurczaków)

76 SCRUM Przebieg sprintu w SCRUM: 4. Retrospekcja – ostatni dzień cyklu, maksymalnie 3 godz. - tylko członkowie zespołu (już po wyjściu kurczaków) - Co poszło dobrze podczas sprintu? Co może zostać poprawione? Cel: poprawienie funkcjonowania zespołu i wdrożenia SCRUM

77 Przykładowy projekt: „Labirynt” Aplikacja konsolowa zaprojektowana zgodnie ze wzorcem architektonicznym MVC, czyli Model-View-Controler Model – dane i logika labiryntu Widok – moduł rysujący labirynt w konsoli Kontroler – przyjmuje wejście z klawiatury, modyfikuje model Model WidokKontroler aktualizujemodyfikuje Użytkownik używa jest oglądany

78 Architektura MVC Kontrola oraz przepływ informacji między modułami aplikacji w architekturze MVC Model WidokKontroler aktualizujemodyfikuje Użytkownik używa jest oglądany

79 Architektura MVC Jest wiele wersji samego MVC (+ MVP) My zaimplementujemy wersję z pasywnymi modelem i widokiem (passive) oraz nadzorującym kontrolerem (supervising) lepiej pasujący do konsoli (bez zdarzeń) Kontrolera zredukujemy do funkcji main Model WidokKontroler aktualizuje modyfikuje Użytkownik używa jest oglądany

80 Przykładowy projekt: „Labirynt”

81 Model (klasa Labirynt ) Pasywny model przechowujący stan aplikacji VC++: Solution Explorer, View Class Diagram

82 Model (klasa Labirynt ) Klasy modelu (C++) class MiejsceWLabiryncie { public: virtual RezultatPróbyWejścia SpróbujWejść() = 0; virtual int Wejdź(int indeksBieżącejKomórki) { return -1; } virtual bool Otwórz() { return false; } }; class Komórka : public MiejsceWLabiryncie {... enum RezultatPróbyWejścia { Nieokreślony = 0, Powodzenie, NieMożnaWejść, Zamknięte }; enum Kierunek { Północ = 0, Południe = 1, Wschód = 2, Zachód = 3 }; enum StanGry { Niezakończona = 0, Śmierć, Wygrana };

83 Model (klasa Labirynt ) Klasy modelu (C++) class Komórka : public MiejsceWLabiryncie { private: int indeks; MiejsceWLabiryncie* sąsiednieMiejsca[4]; public: Komórka(int indeks); MiejsceWLabiryncie* PobierzMiejscePoStronie(Kierunek kierunek) const; void PowiążZMiejscem(Kierunek kierunek, MiejsceWLabiryncie* miejsce); virtual RezultatPróbyWejścia SpróbujWejść(); virtual int Wejdź(int indeksBieżącejKomórki); int PobierzIndeks(); bool OtwórzDrzwi(Kierunek kierunek); bool OtwórzDrzwi(); };

84 Model (klasa Labirynt ) Klasy modelu (C++) class Labirynt { private: int liczbaKomórek; PKomórka* komórki; int indeksBieżącejKomórki, indeksCelu; StanGry stanGry = Niezakończona; public: Labirynt(int liczbaKomórek, int indeksPoczątkowejKomórki, int indeksCelu); ~Labirynt(); void DodajKomórkę(int indeks, Komórka* komórka); Komórka* PobierzBieżącąKomórkę(); RezultatPróbyWejścia PrzejdźWKierunku(Kierunek kierunek); void Zakończ(); StanGry PobierzStanGry(); };

85 Widok (klasa Widok ) Klasa widoku (zbiór funkcji bez własnego stanu) #pragma once #include "Model.h" class Widok { private: Labirynt* model; public: Widok(Labirynt* model); static void WyświetlInformacjęOKomórce(Komórka* komórka); void WyświetlInformacjęOBieżącejKomórce() const; static void WyświetlInformacjęOPróbiePrzejściaWKierunku(Kierunek kierunek); void WyświetlInformacjęORezultaciePróbyPrzejścia(RezultatPróbyWejścia) const; void WyświetlInformacjęOPróbieOtwarciaDrzwi() const; void WyświetlInformacjęORezultaciePróbyOtwarciaDrzwi(bool wynik) const; void WyświetlInformacjęOStanieGry() const; };

86 Kontroler (funkcja main ) #pragma once #include "Model.h" #include "Widok.h" class Kontroler { protected: Labirynt* model; Widok* widok; void SpróbujPrzejść(Kierunek kierunek); void SpróbujOtworzyćDrzwi(); public: Kontroler(void); ~Kontroler(void); void Uruchom(); };

87 Funkcja main Funkcja main widzi tylko kontroler. Kontroler tworzy instancje modelu i widoku: #include "Kontroler.h" int main(int argc, char* argv[]) { Kontroler kontroler; kontroler.Uruchom(); return 0; }

88 Przykładowy projekt: „Labirynt” Piszemy kod C#…

89 Przykładowy projekt: „Labirynt” Zadania domowe / dwa konkursy (1-3, 4): 1.Do widoku dodać funkcję rysującą bieżącą komórkę (ściany np. za pomocą znaków * ) 2.Przygotować alternatywny widok pokazujący całą mapę z bieżącą komórką oznaczoną # 3.Przygotować zestaw testów jednostkowych dla modelu i widoku (100% pokrycia) 4.Przygotować alternatywny widok korzystający z OpenGL (konkurs)

90 Wzorce konstrukcyjne Wzorce pozwalające oddzielić proces tworzenia instancji obiektów od jego definicji: Budowniczy (Builder) Fabryka abstrakcyjna (Abstract Factory) Metoda wytwórcza (Factory Method) Prototyp (Prototype) Singleton (Singleton)

91 Budowniczy (Builder) Założenia: Model posiada klasę organizującą ( Labirynt ) oraz kilka klas dodatkowych ( Komórka, Ściana, itd.) Cel: 1. Wydzielenie kodu służącego do budowy złożonego produktu (u nas obiektu modelu) z jego klasy 2. Przesłonięcie szczegółów implementacji modelu (tzw. reprezentacji wewnętrznej). 3. Korzystanie z różnych budowniczych prowadzi do tworzenia różnych produktów bez zmiany kodu funkcji tworzącej i zasadniczej struktury produktu

92 Budowniczy (Builder) Implementacja: Do modelu dodana zostaje klasa służąca tylko do stopniowego budowania złożonej instancji głównej klasy modelu. Po zmianach ważne będą już tylko dwie klasy modelu: Labirynt i BudowniczyLabiryntu Nazwy używane w kontekście tego wzorca: Kontroler – Director, kierownik BudowniczyLabiryntu – Builder, budowniczy StdBudowniczyLabiryntu – Concrete Builder Labirynt – Product, produkt

93 Budowniczy (Builder)

94 Budowniczy (Builder)

95 Budowniczy (Builder) Zadania domowe (1) i konkursy (2, 3): 1.Przygotować budowniczego labiryntu, który zamiast tworzyć labirynt jedynie liczy komórki i drzwi, a na końcu wyświetla uzyskane liczby. 2.Ukryj w przestrzeni klasy tworzące tzw. wewnętrzną reprezentację (klasy inne niż Labirynt i klasę zawierającą budowniczego). 3.Przygotować budowniczego dla labiryntu złożonego z foremnych trójkątów na zamkniętym pasie. Użyć PBC w jednym kierunku (konkurs).

96 Metoda wytwórcza (Factory method) Założenia: W odróżnieniu od budowniczego chcemy zmieniać nie zawartość złożonego produktu, a móc wybierać między różnymi klasami produktu Cel: 1. Interfejs do tworzenia różnych produktów (ale bez tworzenia nowej klasy wytwórcy) 2. Możliwość rozszerzania o nowe typy produktów 3. Stworzenie wiele „wirtualnych konstruktorów” dla szczegółowych klas modelu

97 Metoda wytwórcza (Factory method) Implementacja: W klasie kontrolującej aplikację (u nas w kontrolerze) stworzymy metody tworzące elementy labiryntu i sam labirynt. Klasa zawierająca metody – Wytwórca. Można tworzyć klasy potomne Wytwórcy/Kontrolera zmieniając zasady gry i modyfikując elementy labiryntu Nazwy używane w kontekście tego wzorca: Kontroler – Creator, wytwórca StandardowyKontroler – Concrete creator Labirynt - Product StandardowyLabirynt – Concrete product

98 Metoda wytwórcza (Factory method)

99 Fabryka abstrakcyjna (Abstract factory) Założenia: W odróżnieniu od budowniczego chcemy zmieniać nie zawartość złożonego produktu, a móc wybierać między różnymi klasami produktu (= metoda wytw.) Cel: 1. Zebranie metod wytwórczych dla rodziny produktu w jednej klasie (często singletonie) 2. Stworzenie interfejsu do tworzenia obiektów (fabryka abstrakcyjna) z możliwością jej nadpisywania w fabryce konkretnej

100 Fabryka abstrakcyjna (Abstract factory) Implementacja: Tworzymy nową klasę zawierającą zbiór metod wytwórczych tworzących poszczególne elementy labiryntu Nazwy używane w kontekście tego wzorca: FabrykaLabiryntu – Abstract factory StandardowaFabrykaLabiryntu – Concrete factory, fabryka konkretna Labirynt – Abstract product StandardowyLabirynt – Concrete product Kontroler – Client

101 Fabryka abstrakcyjna (Abstract factory)

102 Singleton (Singleton) Założenia: Możliwe jest utworzenie tylko jednej instancji klasy Implementacja: Stworzymy klasę potomną fabryki abstrakcyjnej, która będzie przechowywała prototypy i zwracała ich kopie na żądanie

103 Singleton (Singleton) Prywatna instancja klasy Ukryty (chroniony) konstruktor Metoda pozwalająca na pobranie jednej, przechowywanej instancji Inny sposób implementacji: klasa zawierająca wyłącznie statyczne pola i metody

104 Singleton (Singleton) Przykładowy kod C++: #pragma once class Singleton { private: static Singleton* instancja; protected: Singleton() {}; //ukryty konstruktor public: static Singleton* PobierzInstancję() { if (instancja == 0) //lazy initialization instancja = new Singleton(); return instancja; } };

105 Singleton (Singleton) Przykładowy kod C#: class Singleton { private static Singleton instancja; protected Singleton() {}; //ukryty konstruktor public static Singleton Instancja { get { if (instancja == null) //lazy initialization instancja = new Singleton(); return instancja; } };

106 Singleton (Singleton) Przykładowy kod C# (w wielu wątkach): class Singleton { private static lockObject = typeof(Singleton); private static Singleton instancja; protected Singleton() {}; //ukryty konstruktor public static Singleton Instancja { get { lock(lockObject) { if (instancja == null) //lazy initialization instancja = new Singleton(); return instancja; }

107 Singleton (Singleton) Problemy: Wzorzec krytykowany za - odmiana zmiennych globalnych - kontrolę tworzenia i cyklu życia - powoduje „ciasne” wiązania w kodzie Singleton vs dziedziczenie Zadanie domowe (1) i konkursy (2): 1.Zmodyfikować wzorzec Singletonu w taki sposób, aby możliwe było tworzenie N instancji 2.Znaleźć sposób, aby uniemożliwić niezależne tworzenie klas potomnych (C#: modyfikator sealed )

108 Prototyp (Prototype) Założenia: Fabryka, która kopiuje przechowywane wzorcowe instancje produktów, czyli prototypy Konsekwencje: 1. Produkty muszą mieć możliwość klonowania (konstruktor copy i/lub metoda Clone) 2. Inicjowanie stanu klonów już po ich utworzeniu (a więc nie przez konstruktor!) 3. Można zmieniać produkt w trakcie działania programu (wystarczy podmienić prototyp)

109 Prototyp (Prototype) Implementacja: Stworzymy alternatywną fabrykę abstrakcyjną, przechowującą prototypy i zwracającą ich kopie na żądanie Nazwy używane w kontekście tego wzorca: MiejsceWLabiryncie – Prototype, prototyp (deklaruje metodę Klonuj ) Komórka, Ściana, Drzwi – Concrete prototype, produkt konkretny (definiują metodę Klonuj ) FabrykaLabiryntuZPrototypami – Client (przechowuje instancje prototypów i je klonuje)

110 Prototyp (Prototype)

111 Prototyp (Prototype) Zadanie domowe (1) i konkurs (2): 1.Rozszerzyć fabrykę o prototyp labiryntu 2.Zmienić kod fabryki tak, żeby przechowywała dowolną tablicę prototypów

112 Wzorce konstrukcyjne - zadania 1.Poprzez refaktoryzację doprowadź projekt 'Wąż' do architektury MVC. 2.W aplikacji Windows Forms lub WPF zdefiniować metodę wytwórczą, która będzie tworzyła przycisk, umieszczała go w zadanym miejscu formy lub panelu i zmieniała jego kolor na podany w argumencie. Kliknięcie przycisku powinno powodować zmianę koloru przycisku na czarny. 3.Zdefiniuj metodę wytwórczą, która buduje zielono-czerwoną szachownicę o podanym w argumencie rozmiarze, w której klikanie przycisków powoduje zmianę ich koloru na czarny. 4.Stwórz fabrykę abstrakcyjną, która buduje szachownicę. Kolory będą podane w fabryce konkretnej. 5.Zmień fabrykę w fabrykę z prototypami, w której wzorzec przycisku (bez koloru) podawany jest przez argument konstruktora.

113 Wzorce strukturalne Wzorce dotyczące relacji między klasami, rozwiązujące typowe problemy systemów z wieloma klasami: Adapter (Adapter) Dekorator (Decorator) Fasada (Facade) Kompozyt (Composite) Most (Bridge) Pełnomocnik (Proxy) Pyłek (Flyweight)

114 Adapter (Adapter) Założenia (adapter klasowy): Client używa obiektów pochodnych względem Target. Chcemy użyć także Adaptee, ale ma inny interfejs. Tworzymy Adapter typu Target (relacja jest), który korzysta z obiektu Adaptee (wielodziedziczenie).

115 Adapter (Adapter) Implementacja Nowy kod: funkcja WIoF(WielokątForemny*) Istniejący kod: klasa Prostokąt Chcemy użyć nowej funkcji dla istniejącej klasy. W.NET: interfejs określający wymagania klienta (ITarget) Nazwy używane w kontekście tego wzorca: WielokątForemny – Target, element docelowy WyświetlInformacjeOFigurze – Client Prostokąt – Adaptee, klasa dostosowywana ProstokątForemny – Adapter, kl. dostosowująca

116 Adapter (Adapter) Adapter klasowy i adapter obiektowy – Adapter obiektowy nie adaptuje klasy (dziedziczeniem prywatnym), a obiekt tej klasy przekazywany przez argument konstruktora – Adapter klasowy nie działa dla klas potomnych Adaptee, a obiektowy – tak – Adapter klasowy może przesłaniać funkcje Adaptee, w adapterze obiektowym to jest trudne Adapter dwukierunkowy (przezroczystość) Adaptery dołączalne – umieją dynamicznie, na podstawie dostarczonych danych, pobierać dane z Adaptee, którego typ nie jest ustalony przy kompilacji

117 Dekorator (Decorator) Założenia: Chcemy dodać funkcjonalność/obowiązek do jednego obiektu, bez zmieniania jego klasy. Włożymy go w lekką otoczkę, która doda funkcję.

118 Dekorator (Decorator) Implementacja Dekorator to klasa dziedzicząca z Component (interfejs) i mająca Component jako pole (na przechowanie Concrete component). Udostępnia metody i pola tego pola modyfikując je lub dodając. Nazwy używane w kontekście tego wzorca: Napój – Component Herbata, Kawa – Concrete component NapójZDodatkiem – Decorator NapójZPlastremCytryny – Concrete decorator

119 Fasada (Facade) Założenia: Dodatkowa klasa udostępniająca metody wyższego poziomu złożone z wielu wywołań metod biblioteki lub podsystemu klas. Tworzy ujednolicony prosty interfejs. (na podstawie rysunku z G4)

120 Fasada (Facade) Przykład: Realizowanie zamówień: 1. Sprawdzenie dostępności towaru 2. Wypełnienie formularza 3. Zapłacenie rachunku 4. Dostarczenie Fasada: Złóż zamówienie Nazwy używane w kontekście tego wzorca: NapojeMenu – Facade Herbata, NapójZCytryną, itd. - klasy podsystemu

121 Kompozyt (Composite) Cel: Pozwala na budowanie z obiektów struktury drzewa (hierarchia część-całość)

122 Kompozyt (Composite) Przykład: Nazwy używane w kontekście tego wzorca: IPracownik – Component Pracownik – Leaf Kierownik – Composite funkcja main – Client

123 Kompozyt (Composite) Zalety: Nadrzędny element (korzeń drzewa) reprezentuje wszystkie elementy podrzędne (uproszczenie interfejsu, a więc i kodu klienta) Można definiować wiele liści (np. klasy potomne po Pracownik) i wiele kompozytów (np. klasy potomne po kierownik) – możliwość rozszerzania zbioru klas Kompozyty z cyklami: Zwykle kompozyt kojarzymy z drzewami, ale może zawierać cykle – należy to uwzględnić przy korzystaniu z rozwiązań bazujących na rekurencjach.

124 Kompozyt (Composite) Zadanie domowe: Zadeklarować w interfejsie IPracownik i zaimplementować w klasie Pracownik metodę Count zliczającą liczbę elementów w podstukturze. Uwzględnić możliwość istnienia cykli w strukturze kompozytu (gdy pracownik staje się np. dziekanem).

125 Kompozyt (Composite) Konkursy: 1.Zmodyfikować kod w taki sposób, aby metoda WyświetlInformacje lepiej pokazywała strukturę obiektów (drzewo). Jak przekazać stopień zagnieżdżenia? 2.Zaimplementować w klasie Kierownik interfejs IEnumerable, który umożliwia umożliwić pobranie iteratora ( IEnumerator ) pozwalającego na przeglądanie całej struktury podwładnych (w dowolnym poziomie zagnieżdżenia). Uwzględnić ewent. obecność cykli.

126 Most (Bridge) Cel: Rozdziela interfejs od implementacji, także dziedziczenia (bogate uchwyty do klas – handle/body class)

127 Most (Bridge) Założenia: Skrzyżowanie dwóch lub więcej katerogii (np. klasy różnego typu implementowane dla różnych platform) powoduje „zoo” klas i zależności. Jeżeli oddzielimy i ukryjemy implementacje, to podział samym „interfejsów” klas jest prostszy. Most to nazwa dla relacji między abstrakcją (ogólnym interfejsem) a abstrakcyjną implementacją Dobry przykład: figury rysowane w różnych systemach graficznych (podział figur vs API do ich rysowania) Nasz przykład: relacja pilot-telewizor(y)

128 Most (Bridge) Przykład: Nazwy używane w kontekście tego wzorca: Shape – Abstraction Rectangle, Circle – Refined Abstraction Drawing – Implementor WinDrawing, XDrawing – Concrete Implementor

129 Pełnomocnik (Proxy) Cel: „Cieńki” pełnomocnik „grubej” klasy (inny kontekst niż most) (na bazie G4)

130 Pełnomocnik (Proxy) Cel: „Cieńki” pełnomocnik „grubej” klasy (inny kontekst niż most) (na bazie G4)

131 Pełnomocnik (Proxy) Przykład: Nazwy używane w kontekście tego wzorca: ŚrodkiPłatności - Subject CzekBankowy – Proxy Gotówka, PieniądzeWBanku – Real Subject https://sourcemaking.com/design_patterns/proxy

132 Pełnomocnik (Proxy) Założenia: Pełnomocnik wirtualny - odraczanie kosztów związanych z ewentualnym tworzeniem „grubego” obiektu (por. leniwa inicjacja) Zdalny pełnomocnik obiektu z innego procesu lub komp. Pośrednik zabezpieczający – celem jest zabezpieczenie obiektu lub programu (sprawdzanie blokad), a nie ograniczenie użycia zasobów Inteligentne wskaźniki (referencje) – realizują także powyższe cele Pośrednik danych – częsty przykład, unifikacja

133 Pełnomocnik (Proxy) Leniwa inicjacja class MathProxy : public IMath { private: Math* math; Math* getMathInstance() { if (!math) math = new Math(); return math; } public: MathProxy() :math(NULL) {}

134 Pyłek (Flyweight) Cel: Zmniejszyć zużycie pamięci zmarnowanej na obsługę wielu powielonych obiektów (por. prosta kompresja) (na bazie G4)

135 Pyłek (Flyweight) Warunki stosowania: Aplikacja korzysta z dużej liczby powtarzających się obiektów Koszty przechowywania tych obiektów są duże Stan obiektu można zapisać poza nim Nie ma porównywania obiektów Porównaj z najprostszą metodą kompresji przez kodowanie słownikowe (LZ/Lempel-Ziv, ZIP, RAR, PNG), słownik statyczny (określony przez klasy pyłków)

136 Pyłek (Flyweight) Przykład: Nazwy używane w kontekście tego wzorca: Znak – Flyweight ZnakA, ZnakB,... – ConcreteFlyweight FabrykaZnaków – FlyweightFactory main, document – Client (na bazie G4)

137 Wzorce operacyjne Wzorce dotyczące dzielenia odpowiedzialności między współpracującymi ze sobą obiektami (porządkują złożone przepływy sterowania): Interpreter (Interpreter) Iterator (Iterator) Łańcuch zobowiązań (Chain of responsibility) Mediator (Mediator) Metoda szablonowa (Template method) Obserwator (Observer) Odwiedzający (Visitor) Pamiątka (Memento) Polecenie (Command) Stan (State) Strategia (Strategy)

138 Interpreter (Interpreter) Cel: Stworzenie mini-języka używanego w programie

139 Interpreter (Interpreter) Implementacja: Tworzona jest klasa główna reprezentująca cały interpreter oraz klasy potomne reprezentujące poszczególne reguły gramatyki. To w efekcie interpretacji łańcucha prowadzi do powstania drzewa syntaktycznego złożonego z obiektów reguł

140 Interpreter (Interpreter) Przykład: liczby w notacji rzymskiej liczbaRzymska ::= {tysiące} {setki} {dziesiątki} {jedności} tysiące, setki, dziesiątki, jedności ::= dziewięć | cztery | {pięć} {jeden} {jeden} {jeden} dziewięć ::= "CM" | "XC" | "IX" cztery ::= "CD" | "XL" | "IV" pięć ::= 'D' | 'L' | 'V' jeden ::= 'M' | 'C' | 'X' | 'I' Nazwy używane w kontekście tego wzorca: InterpreterLiczbRzymskich – wyrażenie abst. InterpreterTysięcy,... – wyrażenie pośrednie liczbyRzymskie – Context (informacje globalne) main – Client

141 Iterator (Iterator) Cel: Umożliwia sekwencyjny dostęp do elementów agregatu bez konieczności eksponowania wewnętrznej struktury. Możliwość iteracji niezależnie/równolegle, różnego typu https://sourcemaking.com/design_patterns/iterator

142 Iterator (Iterator) Standardowe metody iteratora: template class Iterator { public: virtual void First() = 0; virtual void Next() = 0; virtual bool IsDone() = 0; virtual Element CurrentElement() = 0; protected: Iterator(){} }; Ukryty konstruktor – metoda wytwórcza w agregatorze

143 Iterator (Iterator) Implementacja z rozdzieleniem iteratora i agregatu:

144 Iterator (Iterator) Przykład: AbstrakcyjnyStos, Iterator - abstrakcje Stos – prosta implementacja z tablicą do przechow. StosIterator – pozwala na przebiegnięcie wszystkich zapamiętanych elementów (wbrew naturze stosu) Nazwy używane w kontekście tego wzorca: Iterator – Iterator. StosIterator – ConcreteIterator AbstrakcyjnyStos – Aggregate Stos – ConcreteAggregate

145 Iterator (Iterator) W platformie.NET jest interfejs IEnumerable, który kontaktuje metodę GetEnumerator zwracającą iterator implementujący interfejs IEnumerator. Interfejs IEnumerator deklaruje: własność Current zwracającą bieżący elment typu T, metodę MoveNext przesuwającą „karetkę” na następną pozycję (na ostatnim elemencie zwr. false ), metodę Reset przesuwającą karetkę na oryginalną pozycję Pętla foreach, rozszerzenia LINQ

146 Iterator (Iterator) Dostęp do kolekcji.NET z wielu wątków: Problemem pojawia się jeżeli iterator przebiega kolekcję w jednym wątku, a jednocześnie inny wątek ją modyfikuje. Podejścia: 1. Użycie metody Synchronized kolekcji do pobrania kopii kolekcji wrażliwej na zmiany  zgłaszamy wyjątek 2. Listę pobieraną przez Synchronized możemy przebiec pętlą for bez użycia iteratora  nieaktualna 3. Polecenia lock równocześnie w miejscu użycia iteratora i metodzie pozwalającej na modyfikacje  wolne 4. Tworzenie płytkiej kopii kolekcji i iteracja po niej (por. 2)

147 Iterator (Iterator) Iterator dla kompozytu: 4. Tworzenie płytkiej kopii kolekcji i iteracja po niej (por. 2)

148 Iterator (Iterator) Zadania domowe: 1. Niech klasa Kierownik (wzorzec kompozyt) implementuje int. IEnumerable pozwalający na iterowanie po podwładnych. Uwzględnij możliwość obecności cykli. 2. Dla stosu z przykładu ilustrującego wzorzec iterator przygotować dwa alternatywne iteratory: - przeskakujący co dwa elementy, - iterujący od końca tablicy.

149 Łańcuch zobowiązań (Chain of Responsibility) Cel: Osłabienie wiązania klienta zgłaszającego żądanie (request), czyli wywołania metody lub zgłaszanie zdarzenia z obiektem obsługującym (handler) poprzez ustawienie modyfikowalnego zbioru obiektów obsługujących

150 Łańcuch zobowiązań (Chain of Responsibility) Implementacja: Implementacja podobna do kolejki (ale może być np. kompozyt). Por. do zdarzeń trasowanych (wł. Handled ), haki w WinAPI. Por. z potokiem: ( wyjście = trzy(dwa(jeden(wejście) ). Dowolność w ustawieniu sposbu obsługi (wszystkie, jeden, wybrany) https://sourcemaking.com/design_patterns/chain_of_responsibility

151 Łańcuch zobowiązań (Chain of Responsibility) Wada: Nie ma gwarancji obsłużenia żądania (wśród obiektów może zabraknąć takiego, który potrafi obsłużyć to konkretne żądanie) Klient ostatecznie nie wie, czy żądanie zostanie obsłużone żądanie, czy w ogóle lub ile razy Nazwy używane w kontekście tego wzorca: HandlerBazowy – Handler, obiekt obsługujący, Handler1,.. – ConcreteHandler, obiekt obsługujący main – Client

152 Mediator (Mediator) Cel: Zmniejszyć liczbę powiązań między równorzędnymi elementami systemu (podgrupami). Typowe: GUI, redukcja plątaniny metod zdarzeniowych https://sourcemaking.com/design_patterns/mediator

153 Mediator (Mediator) Cel: Mediator może także pełnić rolę strażnika integralności stanów obiektów zdefiniowanych w kodzie, który ma otaczać (integracja relacji) https://sourcemaking.com/design_patterns/mediator

154 Mediator (Mediator) Przykład: Klasyczna implementacja listy, w której każdy element przechowuje wskaźnik do następnego elementu stwarza problemy przy operacjach: dodawania, wstawiania i usuwania. Aby w ogóle usunąć relacje między elementami listy dodamy organizujący je obiekt – mediator. Nazwy używane w kontekście tego wzorca: Lista – Mediator Nie będzie Mediator vs ConcreteMediator

155 Metoda szablonowa (Template Method) Cel: Implementacja rodziny algorytmów różniących się szczegółami (np. przygotowywanie pizzy: ciasto -> dodatki -> pieczenie). Kontrola procesu pozostaje w klasie abstrakcyjnej. Podstawowa technika polimorfizmu z powtórnym użyciem kodu.

156 Metoda szablonowa (Template Method) Przygotowywanie pizzy – dwa przykładowe przepisy: (na podstawie referatu Łukasza Kiełczykowskiego) Margherita 1. Przygotuj cienkie ciasto. 2. Dodaj sos pomidorowy. 3. Dodaj mozzarelle. 4. Dodaj bazylię i trochę oliwy. 5. Piecz przez 15 minut. Sycylijska 1. Przygotuj grube ciasto. 2. Dodaj ostry sos. 3. Dodaj oliwki i kapary. 4. Dodaj mieszankę przypraw. 5. Piecz przez 20 minut. Abstrakcja 1. Przygotuj ciasto. 2. Dodaj sos. 3. Połóż dodatki 4. Dodaj przyprawy. 5. Piecz

157 Metoda szablonowa (Template Method) Uwagi: Ciekawe źródło: articles/inheritanceVsDelegation Czasem można i opłaca się implementację Strategii (podobne algorytmy zaimplementowane w osobnych klasach ze wspólnym interfejsem) zastąpić implementacją opartą na Metodzie Szablonowej. W ten sposób unikamy powielania kodu (DRY). Metody szablonowej zwykle nie można wywołać z konstruktora klasy – zawiera odwołania do metod czysto wirtualnych (chyba, że zadbamy o domyślne implementacje wszystkich metod)

158 Metoda szablonowa (Template Method) Nazwy używane w kontekście tego wzorca: Pizza – AbstractClass, zawiera metodę szablonową Margherita, Sycylijska – ConcreteClass main – Client

159 Obserwator (Observer) Cel: Rozluźnienie wiązania między zależnymi od siebie klasami (dwiema lub wieloma) przez zastąpienie bezpośrednich odwołań relacją publikuj-subskrybuj https://sourcemaking.com/design_patterns/observer

160 Obserwator (Observer) Typowy przykład: model widoku i reagujące na zmiany jego stanu widoki (wzorzec obecny w MVC, MVVM i innych z tej rodziny) Porównaj INotifyPropertyChanged i INotifyCollectionChanged z platformy.NET (WPF) i platformy WinRT Nazwy używane w kontekście tego wzorca: Model – Subject, interfejs podmiotu lub sam podmiot Model1, Model2 – ConcreteSubject (niekonieczne) Widok – Observer, interfejs obserw. z met. Aktualizuj WidokTabela, WidokWykres – ConcreteObserver

161 Obserwator (Observer) Zdarzenia jako implementacja wzorca obserwator: button.Click += new EventHandler(o.metoda) button – instancja obserwabli, źródło danych EventHandler – delegacja, deklaracja typu metody o – inny obiekt, nawet z innej warstwy systemu (ale może być również this ) metoda – obserwator, metoda zdarzeniowa reagująca na zmiany += – subskrypcja powiadamiania o zmianach -= – rezygnacja z subskrypcji

162 Obserwator (Observer) Reactive Extensions (Rx) - biblioteka ułatwiająca programowanie asynchroniczne i oparte na zdarzeniach skupiające się na przepływie danych (powiadamianiu o ich zmianach). Przekazywanie zapytań LINQ. Zarządzanie współbieżnością za pomocą planistów. IObservable, IObserver, ISubject Reactive programming – paradygmat programowania, w którym źródło danych aktywnie powiadamia wyższe warstwy o zmianach np. MVVM (zestawiane z paradygmatem interaktywnym, w którym wyższe warstwy same sprawdzają stan danych, czasem muszą to robić cyklicznie)

163 Odwiedzający (Visitor) Cel: Załóżmy strukturę obiektów, np. kompozyt pracowników. Na każdym pracowniku chcemy wykonać pewną operację zależną od jego typu nie zmieniając za oryginalnych klas. Realizujemy ten cel definiując klasę z metodami Visit osobną dla każdego typu pracownika i przyjmującymi instancję odpowiedniego typu pracownika. W pierwotnych klasach konieczna obecność tylko jednej nowej metody Accept. Klasy z pierwotnego drzewa to elementy Klasa (lub klasy - dla różnych operacji) - odwiedzający

164 Odwiedzający (Visitor) https://sourcemaking.com/design_patterns/visitor

165 Odwiedzający (Visitor) Przykład: wydrukujemy informacje o pracownikach z drzewa (kompozytu) Nazwy używane w kontekście tego wzorca: IPracownik – Element Pracownik, Kierownik – ConcreteElement Odwiedzający – Visitor OdwiedzajacyZliczający – ConcreteVisitor rektor – ObjectStructure

166 Odwiedzający (Visitor) Zalety/Wady: Po zaimplementowaniu wzorca Odwiedzający możemy swobodnie dodawać kolejne czynności realizowane na całej strukturze obiektów. Uogólnienie: Wzorzec Visitor można także traktować jako pozostawienie przez projektanta furtki do nowych funkcjonalności bez konieczności modyfikacji istniejącej hierarchii klas. Wówczas ma sens nie tylko dla struktury obiektów, ale nawet dla jednej klasy.

167 Pamiątka (Memeno) Inna nazwa: Znacznik (Token) Cel: Zapis wewnętrznego stanu innego obiektu (źródła) bez jego udostępniania; opis stanu = pamiątka https://sourcemaking.com/design_patterns/memento

168 Przykład: punkty kontrolne (cofnij/ponów), przechowywanie stanu w aplikacjach mobilnych Nazwy używane w kontekście tego wzorca: Licznik – Originator, źródło PamiątkaLicznika – Memento, pamiątka main – zarządca (np. mechanizm cofania) Pamiątka (Memento)

169 Przykład: wstrzymywanie i wznawianie działania aplik. Trwała pamiątka: zapis stanu np. w pliku (savegame), trwałe punkty kontrolne – odmiana backupu aplikacji Za pamiątkę można uznać efekt serializacji obiektu (nie – jeżeli tylko pola publiczne, np. do XML) Memento wielosesyjne – np. zapis stanu obiektu lub aplikacji w chmurze i przywrócenie jej na innym urządzeniu lub choćby w innej sesji Pamiątka (Memento)

170 Polecenie (Command) Inna nazwa: Akcja (Action), Transakcja (Transaction) Cel: zamyka żądanie/funkcję/metodę w formie obiektu, Umożliwia zapamiętywanie (cofanie) i kolejkowanie żądań. Separuje kod wykonywany od klienta, który użyje efektu.

171 Polecenie (Command) Realizacja: przechowywanie wskaźnika do funkcji/metody opcja 1: może także przechowywać parametry wywołania opcja 2: dodatkowa akcja sprawdzająca możliwość uruchom. Przykład: Platforma.NET – klasa RelayCommand w MVVM

172 Pamiątka / Polecenie Zadanie domowe: W aplikacji Notatnik przygotować system Undo/Redo Cofanie (un-do) powinno wykorzystywać pamiątki Ponawianie (re-do) powinno używać polecenia Wprowadź ograniczenie na liczbę możliwych cofnięć Własność Enabled elementów menu Cofnij i Ponów zmieniaj korzystając ze wzorca obserwator.

173 Stan (State) Idea: Skomplikowana funkcjonalność klasy, zależna od parametrów (tj. od aktualnego stanu instancji klasy) rozdzielana jest do osobnych klas reprezentujących funkcjonalność w poszczególnych stanach (na podstawie GoF)

174 Stan (State) Realizacja: Klasa główna przechowuje adresy klas reprezentujących poszczególne stany i deleguje na nie wykonanie żądań własnych metod Przykład: TCPConnection (GoF), Drzwi (Stan = DrzwiZamknięte, DrzwiOtwarte ) Nazwy używane w kontekście tego wzorca: Drzwi – Context, klasa udostępniana klientom StanDrzwi – State, stan – interfejs do kapsułkowania zachowania klasy Drzwi w różnych stanach DrzwiZamkniete, DrzwiOtwarte – poszczeg. stany main – klient

175 Strategia (Strategy) Idea: rodzina algorytmów, każdy reprezentowany przez osobną klasę, które mogą być używane zamiennie Eliminuje switch w jakiejś konkretnej metodzie Inne nazwy: Polityka (Policy) https://sourcemaking.com/design_patterns/strategy

176 Strategia (Strategy) Realizacja: Klasa główna przechowuje adres klasy reprezentującej wybrany algorytm i korzysta z jej metod do realizacji konkretnego żądania (wykonania metody). Wzorzec Strategii może być powielony przy wielu metodach https://sourcemaking.com/design_patterns/strategy

177 Strategia (Strategy) Nazwy używane w kontekście tego wzorca: OdgadywaczLiczby – Context, klasa udostępniana StrategiaZgadywaniaLiczby – Strategy, wspólny interfejs dla wielu konkretnych strategii (używanych do realizacji metody OdgadywaczLiczby::Zgaduj ) StrategiaPoKolei, StrategiaLosowo – implementacje poszczególnych algorytmów main – klient

178 Wzorce spoza książki G4 Wzorzec strukturalny Private Class Data https://sourcemaking.com/design_patterns/private_class_data Cała kategoria wzorców współbieżności: Aktywny obiekt, Asynchroniczne sterowanie przez zdarzenia, Udaremnianie, Blokada z podwójnym zatwierdzaniem, Ochraniane wstrzymywanie, Obiekt monitorujący, Blokada zapisu i odczytu, Zarządca procesów, Pula wątków, Pamięć dla wątków, Reaktor; Antywzorce projektowe

179 Rozkład MVC na proste wzorce Aktywny model / widok – obserwator (widok obserwuje model) Widok / kontroler – strategia (widok pozostawia obsługę reakcji kontrolerowi) Widok – kompozyt (praca z zagnieżdżonymi widokami) Model WidokKontroler aktualizujemodyfikuje Użytkownik używa jest oglądany

180 Inny podział wzorców Wzorce interfejsów: Adapter, Fasada, Kompozyt, Most Wzorce odpowiedzialności: Singleton, Obserwator, Mediator, Pośrednik, Łańcuch odpowiedzialności, Pyłek Wzorce konstrukcyjne: Budowniczy, Metoda wytwórcza, Fabryka abstrakcyjna, Prototyp, Pamiątka Wzorce operacji: Metoda szablonowa, Stan, Strategia, Polecenie, Interpreter Wzorce rozszerzeń: Dekorator, Iterator, Odwiedzający


Pobierz ppt "Wzorce projektowe w C# WWW: Jacek Matulewski Instytut Fizyki, UMK WWW:"

Podobne prezentacje


Reklamy Google