|
Wzorce projektowe
wyróżnia się trzy rodzaje wzorców:
wzorce związane z tworzeniem obiektów (Creational Patterns)
wzorce strukturalne (Structural Patterns)
wzorce zachowania (Behervioral Patterns)
Pierwszy typ wzorców ułatwia zarządzanie tworzeniem obiektów lub ich rodzin, drugi pomaga nadać systemowi odpowiednią strukturę. Trzeci pomaga modelować odpowiednie zachowanie.
Najczęściej używane wzorce to:
Abstract Factory – tworzenie rodzin spokrewnionych obiektów bez określania jakich klas mają być te obiekty. Umożliwia to parametryzację systemu w czasie wykonania. Typowym przykładałem jest zmienianie stylu GUI ale praktyczne zastosowanie jest znacznie szersze.
Singleton – zapewnia, iż w systemie będzie dokładnie jeden egzemplarz danego obiektu.
Prototype – pozwala tworzyć obiekty na podstawie istniejących poprzez klonowanie.
Fascade – pozwala stworzyć interfejs do podsystemu.
Template Method – pozwala na zdefiniowanie szkieletu operacji lub np. procesu biznesowego. Pewne szczegóły, które mogą podlegać zmianom, są definiowane dopiero w klasach potomnych.
Interator – określa sposób dostępu do obiektów będących składnikami złożonych struktur.
State – pozwala na zmianę (w elegancki sposób) zachowania obiektu, gdy jego stan się zmieni.
Strategy – pozwala zdefiniować rodzinę algorytmów, które są wymienialne.
Warto podkreślić, iż wzorce nie są trudne od strony programistycznej czy składniowej. Ich genialność wynika z odpowiedniej struktury. Środki przy pomocy których je zbudowano to:
Delegacja jest mocnym narzędziem, polega ona na tym, że wykonanie metody zostaje „oddelegowane” czyli przesłane do odpowiedniego realizatora. Ponieważ realizatory mogą być (dynamicznie) zmieniane daje to niesamowitą elastyczność. Delegację zazwyczaj stosuje się łącznie z dziedziczeniem. Użycie wzorców tego rodzaju nie jest charakterystyczne dla języka JAVA, choć trzeba pamiętać, iż istnieją również wzorce charakterystyczne dla J2EE.
public class Sorter { private Sorter realizator = null;
public void konfiguruj(Sorter r){ realizator = r;
}
public Object[] sortuj(Object[] o){ if (realizator!==null){
return realizator.sortuj(o);
}else{ //obsługujemy scenariusz alternatywny
}
}
}
class SortowanieSzybkie extends Sorter{
public Object[] sortuj(Object[] o){ //tu implementujemy algorytm sortowania QuickSort
}
}
class SortowanieBabelkowe extends Sorter{
public Object[] sortuj(Object[] o){ //tu implementujemy algorytm sortowania BubleSort
}
}
Inne klasy używają do sortowania obiektu klasy Sorter, który jednak sam niczego nie sortuje, tylko oddelegowuje (musi być skonfigurowany) do konkretnego realizatora, w którym z kolei zaimplementowano konkretny algorytm sortowania. W powyższym przykładzie są 2 realizatory.
Trzeba również pamiętać o antywzorcach tj. o rozwiązaniach, których nie należy powielać: Typowe antywzorce w projektowaniu to:
wywołanie metody przodka w metodzie klasy potomnej
klasy, które „zbyt dużo robią” i mają zbyt dużo metod
zbyt duże rozbicie funkcjonalności pomiędzy zbyt złożoną hierarchię i zbyt silne rozbicie logiki biznesowej na zbyt wiele klas
przeniesienie zbyt wielu lub wszystkich metod z klas z modelu dziedzinowego (biznesowego) do logiki biznesowej. Niektóre architektury np. J2EE stosują takie podejście.
Literatura na temat wzorców:
[GoF] Gamma at al, Design Patterns, Addison – Wesley 1998
[GoFpl] Polskie wydanie: Gamma Erich, Helm Richard, Johnson Ralph, Vlissides John, Wzorce projektowe. Elementy oprogramowania obiektowego wielokrotnego użytku, WNT, ISBN 83-204-3041-0
|