13. Wzorce projektowe

13.1. Przykłady praktyczne

13.1.1. Singleton

Code Listing 13.13. Singleton Design Pattern
class DB:
    connection = None

    def __init__(self):
        pass

    @staticmethod
    def connect():
        if not DB.connection:
            print('Nawiazujemy nowe polaczenie')
            DB.connection = ...

        return DB.connection


# Bedzie sie laczyl do bazy danych
conn = DB().connect()

# uzyje juz istniejacego polaczenia
conn = DB().connect()

13.1.2. Gateway

Code Listing 13.14. Gateway Design Pattern
import datetime
import json
import logging
import os
import requests

log = logging.getLogger(__name__)


class HTTPGateway:
    def __init__(self, username=None, password=None, cache_expiry_days=30, cache_directory='.'):
        self.username = username
        self.password = password
        self.cache_expiry_days = cache_expiry_days
        self.cache_directory = cache_directory

    @staticmethod
    def _get_cache_name_from_url(url):
        return url.replace('/', '-').replace(':', '-')

    def _fetch_from_url(self, url):
        connection = requests.get(url, auth=(self.username, self.password))

        if connection.status_code != 200:
            log.error(f'Cannot fetch from URL: {url}')
            raise ConnectionError
        else:
            log.debug(f'Fetched from {url}')
            return connection.text

    def _fetch_from_cache(self, url):
        cache_name = self._get_cache_name_from_url(url)
        path = os.path.join(self.cache_directory, cache_name)

        with open(path) as file:
            log.debug(f'Reading from cache file {path}')
            return file.read()

    def _set_cache(self, url, data):
        cache_name = self._get_cache_name_from_url(url)
        path = os.path.join(self.cache_directory, cache_name)

        with open(path, 'w') as file:
            log.debug(f'Writing to cache file {path}')
            file.write(data)

    def _cache_invalid(self, url):
        def last_modified_less_than_month_ago(path):
            modification_timestamp = os.path.getmtime(path)
            modification_datetime = datetime.datetime.fromtimestamp(modification_timestamp)
            now = datetime.datetime.now()
            return (now - modification_datetime).days < self.cache_expiry_days

        cache_name = self._get_cache_name_from_url(url)
        path = os.path.join(self.cache_directory, cache_name)

        if os.path.isfile(path) and last_modified_less_than_month_ago(path):
            return False
        else:
            return True

    def get(self, url):
        if self._cache_invalid(url):
            log.info(f'Will read from URL {url}')
            data = self._fetch_from_url(url)
            self._set_cache(url, data)
        else:
            log.info(f'Will read from cache')
            data = self._fetch_from_cache(url)

        return json.loads(data)


http = HTTPGateway(
    username='username',
    password='password',
    cache_directory='tmp',
    cache_expiry_days=10,
)

# pobranie i ustawienie cache
html1 = http.get('http://python.astrotech.io')

# wczytanie z cache, bez komunikacji z internetem
html2 = http.get('http://python.astrotech.io')

13.1.3. Factory

Code Listing 13.15. Factory Design Pattern
class HttpClientInterface:
    def GET(self):
        raise NotImplementedError

    def POST(self):
        raise NotImplementedError


class GatewayLive(HttpClientInterface):
    def GET(self):
        # zaciagnij informacje o userze
        return ...

    def POST(self):
        # zapytaj po sieci
        pass


class GatewayStub(HttpClientInterface):
    def GET(self):
        return {'imie': 'nazwisko'}


class HttpClientFactory:
    instance = None

    def __init__(self):
        if HttpClientFactory.instance:
            HttpClientFactory.instance = GatewayStub

        return HttpClientFactory.instance


client = HttpClientFactory()
client.GET()

client2 = HttpClientFactory()
client2.GET()
client2.POST()

13.2. Inne wzorce

  1. Wprowadzenie
    • Wartości dobrego oprogramowania
    • ojęcie jakości i jej rodzaje w oprogramowaniu
    • Proces wytwórczy w branży oprogramowania
  2. Analiza i modelowanie obiektowe z wykorzystaniem notacji UML – wstęp
    • Diagram klas
    • Diagram sekwencji i komunikacji
  3. Projektowanie obiektowe
    • Zasady projektowania obiektowego
    • Zasady S.O.L.I.D
    • Zapachy kodu
  4. Wzorce projektowe
    • Idea wzorców
    • Wzorce GoF
    • Inne wzorce - przegląd
    • Zagadnienia związane z refaktoryzacją – wstęp
  5. Wzorce
    • Rodzaje wzorców i ich klasyfikacja
    • Techniki identyfikacji wzorców
  6. Strukturalne wzorce projektowe
    • Adapter (klasowy i obiektowy)
    • Most (ang. Bridge) (obiektowy)
    • Kompozyt (ang. Composite) (obiektowy)
    • Dekorator (ang. Decorator) (obiektowy)
    • Pyłek (ang. Flyweight) (obiektowy)
    • Fasada (ang. Fa ç ade) (obiektowy)
    • Pełnomocnik (ang. Proxy) (obiektowy)
  7. Warsztat analizy aplikacji z wykorzystaniem poznanych wzorców projektowych
  8. Konstrukcyjne wzorce projektowe
    • Metoda wytwórcza (ang. Factory Method) (klasowy)
    • Fabryka Abstrakcyjna (ang. Abstract Factory) (obiektowy)
    • Budowniczy (ang. Builder) (obiektowy)
    • Prototyp (ang. Prototype) (obiektowy)
    • Singleton (obiektowy)
  9. Warsztat analizy aplikacji z wykorzystaniem poznanych wzorców projektowych
  10. Behawioralne wzorce projektowe
  • Łańcuch zobowiązań (ang. Chain of Responsibility) (obiektowy)
  • Polecenie (ang. Command) (obiektowy)
  • Interpreter (ang. Interpreter) (klasowy)
  • Interator (obiektowy)
  • Mediator (ang. Mediator) (obiektowy)
  • Pamiątka (ang. Memento) (obiektowy)
  • Obserwator (ang. Observer) (obiektowy)
  • Stan (ang. State) (obiektowy)
  • Strategia (ang. Strategy) (obiektowy)
  • Metoda szablonowa (ang. Template Method) (klasowy)
  • Odwiedzający (ang. Visitor) (obiektowy)
  1. Warsztat analizy aplikacji z wykorzystaniem poznanych wzorców projektowych
  2. Idiomy języka programowania
  • Pojęcie idiomu językowego
  • Wzorce i idiomy specyficzne dla języka Python
  • Wzorzec EFAP (ang. It’s easier to ask for forgiveness than permission)
  • Wzorzec Metaklasy
  • Borg
  • Klasa domieszkowa w języku Python (ang. Mixin)

13.3. Creational Design Patterns

  • Abstract Factory Pattern

    • A Classic Abstract Factory
    • A More Pythonic Abstract Factory
  • Builder Pattern

  • Factory Method Pattern

  • Prototype Pattern

  • Singleton Pattern

13.4. Structural Design Patterns

  • Adapter Pattern

  • Bridge Pattern

  • Composite Pattern

    • A Classic Composite/Noncomposite Hierarchy
    • A Single Class for (Non)Composites
  • Decorator Pattern

    • Function and Method Decorators
    • Class Decorators
  • Facade Pattern

  • Flyweight Pattern

  • Proxy Pattern

13.5. Behavioral Design Patterns

  • Chain of Responsibility Pattern

    • A Conventional Chain
    • A Coroutine-based Chain
  • Command Pattern

  • Interpreter Pattern

    • Expression Evaluation with eval()
    • Code Evaluation with exec()
    • Code Evaluation using a Subprocess
  • Iterator Pattern

    • Sequence Protocol Iterators
    • Two-argument iter() Function Iterators
    • Iterator Protocol Iterators
  • Mediator Pattern

    • A Conventional Mediator
    • A Coroutine-based Mediator
  • Memento Pattern

  • Observer Pattern

  • State Pattern

    • Using State-Sensitive Methods
    • Using State-Specific Methods
  • Strategy Pattern

  • Template Method Pattern

  • Visitor Pattern