INF.04 · Rozdział 2.1
Projektowanie oprogramowania · 2 lekcje

Wzorce projektowe

Sprawdzone rozwiązania powtarzających się problemów w projektowaniu aplikacji.

Kwalifikacja INF.04 · podręcznik WSiP, cz. 2, rozdz. 2.1 (s. 17)
Plan

Co nas czeka na dwóch lekcjach

1 Lekcja 1 · Teoria

  • Po co są wzorce projektowe
  • Definicja i krótka historia (GoF)
  • Budowa wzorca: nazwa, problem, rozwiązanie, konsekwencje
  • Trzy grupy wzorców
  • Przegląd 8 wzorców z podręcznika
  • Ćwiczenie: dopasuj wzorzec do sytuacji

2 Lekcja 2 · Praktyka

  • Szybki quiz powtórkowy
  • Adapter i Obserwator w Pythonie
  • Zadanie: rozpoznaj wzorzec w kodzie
  • Mini-projekt: powiadomienia o ocenach
  • Sprawdź swoją wiedzę + praca domowa
Lekcja 1 · Wprowadzenie

Po co wymyślać koło od nowa?

Programiści na całym świecie rozwiązują te same problemy: jak tworzyć obiekty, jak łączyć klasy, jak powiadamiać o zmianach.

Zespół A+Zespół B+Zespół C→ten sam problem→Wzorzec
Definicja

Czym jest wzorzec projektowy?

Wzorzec projektowy to sprawdzone w praktyce rozwiązanie problemu projektowania oprogramowania. Zwykle jest to szkic klas i powiązań między nimi.

1 · Łatwiejsze tworzenie

gotowy schemat zamiast pustej kartki

2 · Łatwiejsza modyfikacja

zmiany w jednym miejscu, bez efektu domina

3 · Czytelny kod

także gdy w projekcie zmieniają się programiści

Trochę historii

Skąd się wzięły wzorce projektowe?

1977 · Christopher Alexander

Architekt opisuje 253 wzorce budowania miast i domów – pomysł „języka wzorców”.

1994 · Gang of Four

Gamma, Helm, Johnson, Vlissides wydają książkę „Design Patterns” – 23 wzorce obiektowe.

Dziś · Wzorce w frameworkach

Korzystają z nich m.in. tkinter, kivy, matplotlib, Django, Android.

Budowa wzorca

Każdy wzorzec opisujemy w 4 częściach

1 · Nazwa

Krótka etykieta, dzięki której zespół szybko się rozumie: „zróbmy tu fasadę”.

2 · Problem

Kiedy stosować wzorzec? Jaka sytuacja w projekcie go wymaga?

3 · Rozwiązanie

Jakie klasy i powiązania tworzymy – szkic, nie gotowy kod.

4 · Konsekwencje

Zalety i koszty: co zyskujemy, a co się komplikuje.

Podział

Trzy grupy wzorców projektowych

Kreacyjne

Jak tworzyć obiekty?

Ukrywają szczegóły tworzenia obiektów.

fabryka · budowniczy · singleton

Strukturalne

Jak łączyć klasy?

Opisują, jak składać klasy i obiekty w większe struktury.

fasada · adapter · kompozyt

Behawioralne

Jak obiekty współpracują?

Opisują komunikację i podział odpowiedzialności.

metoda szablonowa · obserwator · mediator

Wzorce z podręcznika

Osiem często używanych wzorców

WzorzecGrupaCo robi
FabrykaKTworzy obiekty bez podawania konkretnej klasy
BudowniczyKSkłada złożony obiekt krok po kroku
FasadaSProsty interfejs do złożonego systemu
AdapterSDopasowuje niezgodny interfejs do oczekiwanego
KompozytSDrzewo obiektów traktowane jak jeden obiekt
Metoda szablonowaBStały szkielet algorytmu, kroki nadpisują podklasy
ObserwatorBPowiadamia subskrybentów o zmianie stanu
MediatorBObiekty komunikują się przez pośrednika

K – kreacyjny · S – strukturalny · B – behawioralny

Wzorce w życiu codziennym

Znasz je, choć o tym nie wiesz

Fasada

Recepcja w hotelu – jedna osoba załatwia pokój, sprzątanie i taksówkę.

Adapter

Przejściówka do gniazdka – wtyczka z UK działa w polskim gniazdku bez przeróbek.

Obserwator

Subskrypcja kanału – kanał publikuje film, wszyscy subskrybenci dostają powiadomienie.

Budowniczy

Zestaw w restauracji – zamówienie krok po kroku: kanapka, dodatek, napój.

Mediator

Wieża kontroli lotów – samoloty nie rozmawiają ze sobą, każdy gada z wieżą.

Fabryka

Automat z napojami – wybierasz numer, automat sam wydaje właściwy produkt.

Konsekwencje

Zalety i pułapki stosowania wzorców

Zalety

  • Wspólny język w zespole
  • Sprawdzone, przetestowane rozwiązania
  • Kod łatwiej rozbudowywać i utrzymywać
  • Nowa osoba szybciej rozumie projekt
  • Łatwiej czytać kod bibliotek i frameworków

Pułapki

  • Wzorzec „na siłę” tam, gdzie wystarczy prosta funkcja
  • Więcej klas i plików – kod może się rozrosnąć
  • Źle dobrany wzorzec utrudnia zmiany
  • Trzeba znać wzorzec, żeby zrozumieć kod
Ćwiczenie · 10 min

Dopasuj wzorzec do sytuacji

  • A. Aplikacja pogodowa ma powiadomić wszystkie widżety, gdy zmieni się temperatura.
  • B. Stara biblioteka zwraca dane w XML, a nasz program oczekuje słownika (dict).
  • C. Klient chce jednym przyciskiem „Zamów” sprawdzić magazyn, pobrać płatność i zlecić wysyłkę.
  • D. Gra tworzy różne typy przeciwników na podstawie nazwy poziomu.
  • E. Wszystkie raporty mają ten sam układ: nagłówek → treść → stopka, ale różną treść.

Do wyboru

  • Adapter
  • Fabryka
  • Fasada
  • Metoda szablonowa
  • Obserwator
Podsumowanie lekcji 1

Zapamiętaj

1 · Wzorzec projektowy

sprawdzone rozwiązanie typowego problemu projektowego – szkic klas i powiązań

2 · Trzy grupy

kreacyjne · strukturalne · behawioralne

3 · Cel

łatwiejsze tworzenie, modyfikacja i utrzymanie kodu, czytelność

Bilet wyjścia. Na karteczce zapisz: definicję wzorca własnymi słowami · 4 nazwy wzorców · 1 przykład wzorca z życia.
Lekcja 2

Rozpoznajemy wzorce w kodzie

Adapter i Obserwator w Pythonie · zadania praktyczne · mini-projekt.

Rozgrzewka · 5 min

Szybki quiz: prawda czy fałsz?

Wzorzec strukturalny

Adapter – dopasowanie interfejsu

# adapter.py
class StaryTermometr:        # nie możemy go zmienić
    def temperatura_f(self):
        return 98.6          # stopnie Fahrenheita

class AdapterTermometru:
    def __init__(self, termometr):
        self.termometr = termometr
    def temperatura_c(self):    # oczekiwany interfejs
        f = self.termometr.temperatura_f()
        return round((f - 32) * 5 / 9, 1)

czujnik = AdapterTermometru(StaryTermometr())
print(czujnik.temperatura_c())    # 37.0

Problem

Program liczy w °C, a stara klasa podaje tylko °F. Nie chcemy jej przerabiać.

Rozwiązanie

Adapter „opakowuje” stary obiekt i udostępnia metodę w oczekiwanym formacie.

Wzorzec behawioralny

Obserwator – powiadamianie o zmianach

# obserwator.py
class Kanal:
    def __init__(self, nazwa):
        self.nazwa = nazwa
        self.subskrybenci = []
    def subskrybuj(self, widz):
        self.subskrybenci.append(widz)
    def opublikuj(self, tytul):
        for widz in self.subskrybenci:
            widz.powiadom(self.nazwa, tytul)

class Widz:
    def __init__(self, imie):
        self.imie = imie
    def powiadom(self, kanal, tytul):
        print(f"{self.imie}: nowy film na {kanal} – {tytul}")
# użycie
kanal = Kanal("KodujemyPL")
kanal.subskrybuj(Widz("Ola"))
kanal.subskrybuj(Widz("Kuba"))
kanal.opublikuj("Wzorce w Pythonie")
Wynik
Ola: nowy film na KodujemyPL – Wzorce w Pythonie
Kuba: nowy film na KodujemyPL – Wzorce w Pythonie

Kanał nie wie, co robi widz – wywołuje tylko powiadom().

Zadanie 1 · praca w parach

Jaki to wzorzec?

Fragment A

def utworz_wroga(poziom):
    if poziom == "las":
        return Wilk()
    elif poziom == "zamek":
        return Rycerz()
    return Szczur()

wrog = utworz_wroga("zamek")

Fragment B

pizza = (BudowniczyPizzy()
    .ciasto("cienkie")
    .sos("pomidorowy")
    .dodatek("ser")
    .dodatek("pieczarki")
    .zbuduj())
Dla każdego fragmentu podaj: nazwę wzorca · grupę wzorca · jaki problem rozwiązuje.
Zadanie 2 · mini-projekt · 20 min

Dziennik: powiadomienia o ocenach

1 Klasa Dziennik

lista obserwatorów, metody dodaj_obserwatora() i wpisz_ocene(uczen, przedmiot, ocena)

2 Klasa Rodzic

metoda powiadom() wypisuje: „Rodzic: Jan dostał 5 z matematyki”

3 Klasa Wychowawca

powiadamiany tylko o ocenach 1 – wypisuje ostrzeżenie

4 Test

dodaj obu obserwatorów i wpisz co najmniej 3 oceny

Kryteria

  • program działa bez błędów
  • Dziennik nie sprawdza typu obserwatora
  • czytelne nazwy klas i metod
  • dla chętnych: metoda usun_obserwatora()
Sprawdź swoją wiedzę

Pytania z podręcznika i praca domowa

Pytania (podręcznik, s. 23)

  • Wymień cztery nazwy wzorców projektowych.
  • Do czego można użyć wzorca projektowego „fasada”?
  • Wyjaśnij, czym różnią się wzorce kreacyjne, strukturalne i behawioralne.

Praca domowa

Wybierz jeden wzorzec (kompozyt, budowniczy, mediator) i przygotuj notatkę według schematu:

nazwa · problem · rozwiązanie · konsekwencje

+ krótki przykład w Pythonie (do 20 linii) lub przykład z życia codziennego.

Następny temat

2.2 · Fasada

Jak ukryć skomplikowany system za jedną prostą metodą.