Laboratorium z wzorców projektowych - Facade Pattern
Organizacja: refactor-or-die
- Wzorzec: Facade (Fasada)
- Język: Python
- Czas: 1,5 godziny
- Forma pracy: pair programming
Praktyczne poznanie wzorca Facade poprzez refaktoryzację skomplikowanego kodu systemu zamówień pizzy. Celem jest ukrycie złożoności wielu podsystemów za prostym, jednolitym interfejsem.
W pliku src/pizza_order_system.py znajduje się funkcja place_pizza_order(), która realizuje proces składania zamówienia na pizzę. Problem polega na tym, że:
- Klient musi znać 6 różnych klas podsystemów
- Musi znać dokładną kolejność wywołań wszystkich metod
- Musi ręcznie obsługiwać błędy na każdym kroku
- Kod jest nieczytelny i trudny w utrzymaniu
- Każda zmiana w podsystemie wymaga modyfikacji kodu klienta
def place_pizza_order(pizza_type, address, delivery_time, card_number, user_id):
# Krok 1: Sprawdź magazyn
inventory = InventoryManager()
if not inventory.check_availability(pizza_type):
return {"success": False, "error": "Brak pizzy"}
# Krok 2: Oblicz cenę
price_calc = PriceCalculator()
price = price_calc.get_price(pizza_type)
# Krok 3: Płatność
payment = PaymentProcessor()
if not payment.process_payment(card_number, price):
return {"success": False, "error": "Płatność odrzucona"}
# ... i tak dalej przez kolejne 5 krokówTo jest zbyt skomplikowane dla klienta, który po prostu chce zamówić pizzę.
Zrefaktoryzuj kod używając wzorca Facade:
- Stwórz klasę
PizzaOrderFacadew plikusrc/pizza_order_system.py - Klasa powinna mieć metodę
place_order()o sygnaturze:def place_order(self, pizza_type, address, delivery_time, card_number, user_id)
- Metoda powinna zwracać słownik w formacie:
{ "success": True/False, "order_id": ..., # jeśli success=True "pizza_type": ..., "price": ..., "points_earned": ..., "delivery_time": ..., "error": ... # jeśli success=False } - Zmodyfikuj funkcję
place_pizza_order()tak, aby używałaPizzaOrderFacade - Upewnij się, że wszystkie testy przechodzą
- Python 3.8+
- pytest
git clone https://github.com/[WASZE KONTO]/lab01-pizza-driven-development.git
cd lab01-pizza-driven-developmentgit checkout -b lab01_nazwisko1_nazwisko2pip install -r requirements.txtpytest tests/ -vlub:
python3 -m pytest tests/ -vlub:
python -m pytest tests/ -vPracujcie w parach (pair programming), regularnie zamieniając się rolami Driver/Navigator.
pytest tests/ -vgit add .
git commit -m "Refaktoryzacja z użyciem wzorca Facade"
git push origin lab01_nazwisko1_nazwisko2- Utworzenie klasy
PizzaOrderFacadez metodąplace_order() - Uproszczenie funkcji
place_pizza_order()przez użycie Facade - Wszystkie testy przechodzą (
pytest tests/ -v) - Kod jest czytelny i zgodny z ideą wzorca Facade
- Prezentacja rozwiązania na końcu zajęć (2-3 minuty)
lab01-pizza-driven-development/
├── README.md # Ten plik
├── .gitignore # Ignorowane pliki
├── requirements.txt # Zależności Python
├── slides/ # Prezentacja wprowadzająca
│ └── facade_intro.pdf
├── src/
│ └── pizza_order_system.py # Kod do refaktoryzacji
└── tests/
└── test_pizza_order_system.py # Testy jednostkowe
Facade to strukturalny wzorzec projektowy, który dostarcza uproszczony interfejs do złożonego podsystemu.
- System ma wiele współzależnych klas
- Klient potrzebuje tylko podstawowych operacji
- Chcesz odizolować klienta od szczegółów implementacji
- Chcesz uprościć API dla użytkowników zewnętrznych
- Uproszczenie interfejsu
- Redukcja zależności między klientem a podsystemem
- Łatwiejsze utrzymanie kodu
- Elastyczność w modyfikacji podsystemu
- Facade może stać się "god object" jeśli wrzucimy do niej za dużo odpowiedzialności
- Dodatkowa warstwa abstrakcji (minimalny overhead)
Po wykonaniu zadania zastanówcie się:
- Jak Facade wpłynął na czytelność kodu?
- Czy łatwiej byłoby teraz dodać nową funkcjonalność (np. zniżki, kupony)?
- Jakie są potencjalne wady wprowadzenia Facade w tym przypadku?
- Kiedy NIE powinniśmy używać tego wzorca?
W razie pytań: jaroslaw.hryszko@uj.edu.pl
Powodzenia! 🍕