Wzorce projektowe – Pyłek

 maj, 12 - 2020   PHPWzorce Projektowe

Pyłek (flyweight) jest strukturalnym wzorcem projektowy, stosowany wszędzie tam gdzie wymagane jest tworzenie bardzo dużej liczby identycznych lub podobnych obiektów, którymi można zarządzać w jednolity sposób. Artykuł opisuje użycie wzorca oraz wyjaśnia w jakich sytuacjach zasadne jest jego wykorzystanie.

 

 

 

 

Charakterystyka wzorca pyłek

 

Pyłek (flyweight) jest jednym z prostszych wzorców projektowych, którego celem jest tworzenie mniejszej ilości obiektów a co za tym idzie zmniejszenie zużycia zasobów sprzętowych (pamięci i procesora). Może być wykorzystywany wszędzie tam, gdzie istnieje konieczność wykorzystania bardzo dużej ilości takich samych lub podobnych obiektów.

Istotą wzorca jest podział stanów (danych) przechowywanych w obiektach (pyłkach) na wewnętrzne i zewnętrzne:

  • Stan wewnętrzny (współdzielony) jest przechowywany w pyłku i składa się zdanych, które nie zależą od kontekstu. Współdzielenie stanów zmniejsza wykorzystanie pamięci i poprawia efektywność programu, ponieważ dane nie są za każdym razem powielane.
  • Stan zewnętrzny są unikatowe dla każdego obiektu i zmieniają się wraz ze zmianą kontekstu. Za przekazanie do pyłku stanu zewnętrzny odpowiada obiekt klient, wywołujący działanie wzorca.

Poniższy diagram UML przedstawia główne elementy wzorca oraz relacje między nimi.

Mamy tutaj kilka charakterystycznych elementów, wartych omówienia:

  • Interfejs Pyłek – deklaruje metody, przez które konkretne pyłki mogą otrzymać stan zewnętrzny i wykorzystać go do wykonania odpowiedniej logiki.
  • Konkretny Pyłek – obejmuje implementację interfejsu, przechowuje stan wewnętrzny, niezależny od kontekstu działania obiektów.
  • Fabryka Pyłków – odpowiedzialna za tworzenie i zarządzanie pyłkami; dba o to, że pyłki są odpowiednio współużytkowane.
  • Klient – inicjuje działanie logiki aplikacji z wykorzystaniem wzorca, przechowuje referencje do pyłków, oblicza i przetwarza zewnętrzny stan pyłków.

 

 

Przykład zastosowania wzorca pyłek – rysowanie mozaiki kolorowych kształtów

 

Najlepiej działanie wzorca przedstawić na prostym przykładzie. Poniżej przedstawiony został kod aplikacji, która może być wykorzystywana do rysowania mozaiki kolorowych kształtów. Takich kształtów może być tysiące, a więc jest to idealny przykład do wykorzystania omawianego wzorca.

Na wstępie warto się zastanowić co będzie stanem wewnętrznym (współdzielonym) dla naszych pyłków, a co stanem zewnętrznym (unikalnym dla pyłków). Sam kształt (np. okrąg, kwadrat) będzie implementowany przez konkretny pyłek, a każdy z nich będzie zawierał następujące stany: kolor, współrzędna X i współrzędna Y. Kolorów będzie kilka, natomiast współrzędnych może być bardzo wiele (w zależności od wielkości powierzchni na której będziemy rysowali naszą mozaikę). Dla takiej implementacji kolor będzie stanem wewnętrznym, ponieważ jak już zadeklarujemy konkretny kolor kształtu, to on się w żaden sposób nie zmieni i będzie współdzielony dla wszystkich innych kształtów o tym samym kolorze. Współrzędne natomiast będą różne dla każdego z pyłków, więc powinny być dostarczone z zewnątrz.

Po tym krótkim wstępie, przystępujemy do działania. Zacznijmy od prostego interfejsu dla naszych pyłków. Będzie zawierał deklarację konstruktora oraz metody rysującej kształty.

Konstruktor inicjuje kolor, czyli stan współdzielony, natomiast funkcja draw rysuje kształt dla przekazanych współrzędnych.

Dalej przystępujemy do napisania konkretnych pyłków, implementujących przygotowany interfejs. Napiszemy obiekty dla dwóch rodzajów kształtów – okręgu (Circle) i kwadratu (Rectangle) . Konstruktor jest w zasadzie taki sam dla każdego z tych obiektów, dlatego napiszemy również abstrakcyjną klasę, zawierającą wspólny kod pyłków.

Jak narazie nie ma tu nic specjalnego – proste klasy rozszerzający abstrakcję, implementującą wspólny interfejs. Oczywiście dla uproszczenia, sama funkcjonalność rysowania jest pominięta – chodzi tylko o pokazanie istoty działania wzorca.

Teraz przystąpmy do napisania fabryki pyłków, czyli klasy która będzie zarządzała logiką zwracania pyłków – tzn. albo będzie tworzyła nowy obiekt albo zwracała już istniejący egzemplarz w zależności od kształtu i koloru.

Klasa implementuje jedną statyczna metodę getShape, która przyjmuje dwa argumenty typ kształtu i kolor. Na podstawie tych parametrów funkcja sprawdza czy taki pyłek już istnieje i jeżeli tak to zwraca jego egzemplarz, a jeżeli nie to tworzy nowy obiekt pyłku, który oczywiście również zostaje zwrócony. Poszczególne egzemplarze pyłków są zapisywane do tablicy, pełniącej zadanie prostego cache-u.

Ostatnim krokiem jest napisanie prostego klienta, który wykorzysta wszystkie powyżej opisane elementy.

Zadaniem klienta jest wyrysowanie 10 tyś. obiektów o losowym kształcie, kolorze i współrzędnych w obrębie zadanej powierzchni. Kształty zwracane są za pośrednictwem fabryki pyłków, która w zależności od przekazanych parametrów tworzy nowy kształt albo zwraca już istniejący. Gdyby wzorzec nie został wykorzystany, to musielibyśmy utworzyć 10000 unikalnych obiektów. W tym przypadku tworzymy jedynie 16 obiektów (iloraz kształtów i kolorów), które współdzielą wspólny stan, jakim jest kolor.

Wynikiem działania jest nasz mozaika.

 

Powyższy przykład można zobaczyć i pobrać na GitHub: https://github.com/molitorys/design-patterns/tree/master/src/Flyweight/Shapes

 

 

Podsumowanie

 

Wzorzec projektowy pyłek powinien być używany wszędzie tam, gdzie:

  • aplikacja wymaga tworzenia bardzo dużej liczby podobnych obiektów i z uwagi na ich dużą liczbę, koszty przechowywania tych obiektów byłyby duże
  • większość stanów tych obiektów mogą być zapisywane poza nimi, a po przeniesieniu tych stanów na zewnątrz można utworzyć stosunkowo nieliczną grupę obiektów z współdzielonymi stanami wewnętrznymi
  • aplikacja nie jest uzależniona od tożsamości obiektów.

Zalety stosowania tego wzorca są tym większe im więcej pyłków jest współużytkowanych oraz im więcej stanów jest współdzielonych.

Serdecznie zapraszam do zapoznania się z wzorcem projektowym pyłek i zastosowania go w praktyce jak tylko nadarzy się okazja. W razie jakichkolwiek pytań lub nieścisłości, proszę o wpisanie komentarza.


Przeczytaj równierz