Fasada jest wzorcem zaliczającym się do wzorców strukturalnych. Jest to jeden z popularniejszych, a jednocześnie najprostszych wzorców projektowych.
Wyobraź sobie sytuację, gdy masz złożony
system. W pewnym momencie musisz
zapewnić funkcjonalność, która możesz
osiągnąć poprzez złożenie kilku usług oferowanych
przez klasy wchodzące w skład systemu. Może to
wyglądać na przykład tak – naliczanie rabatu do
zakupów klienta:
1 2 3 4 |
$objKlient = new Klient($intIdKlienta); $objKoszyk = new Koszyk($objKlient); $objRabat = new Rabat(); $fltRabat = $objRabat->liczRabat($objKoszyk->getSumaKoszyka()+ $objKlient->getRabatIndywidualny()); |
1 2 3 4 |
Klient klient = new Klient(idKlienta); Koszyk koszyk = new Koszyk(klient); Rabat rabat = new Rabat(); Float Rabat = rabat.liczRabat(koszyk.getSumaKoszyka() + klient.getRabatIndywidualny()); |
Nie ma się czym przejmować, jeśli taka
konstrukcje mamy w jednym miejscu. Jeśli jednak
podobna konstrukcja będzie potrzebna w wielu
miejscach, warto zadbać o to, aby nie kopiować jej
wszędzie za pomocą kombinacji CTRL+C CRTL+V.
W przeciwnym razie w przypadku konieczności
zmodyfikowania powyższej formuły, staniemy
przed koniecznością odszukania poprawianego
fragmentu wszędzie tam gdzie go skopiowaliśmy
i poprawieniem go w tych wszystkich miejscach
z osobna. Tu z pomocą przychodzi fasada.
Przykładowa aplikacja
Tym razem ze względu na sposób działania
wzorca i opis problemu zamieszczony powyżej,
nasza aplikacja będzie od razu opierała się na prezentowanym
wzorcu. Będzie to klasa zarządzająca
przyznawaniem rabatów w sklepie internetowym.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
PHP: class FasadaRabatów { private $objKlient; private $objRabat; private $objKoszyk; private $objZamowienia; public function_construct($intIdKlienta) { $this->objKlient = new Klient($intIdKlienta); $this->objRabat = new Rabat($this->objKlient); $this->objKoszyk = new Koszyk(); $this->objZamowienia = new Zamowienia($this->objKlient); } public function rabatIndywidualny() { return $this->objKlient->getRabatIndywidulany(); } public function rabatOdZakupowWKoszyku() { return $this->objRabat->liczRabat($this->objKoszyk->getWartosc()); } public function getRabatOdWielkosciZamowien() { return $this->objRabat->liczRabat($this->objZamowienia->getSume()); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public class FasadaRabatow { private Klient klient; private Rabat rabaty; private Koszyk koszyk; private Zamowienia zamowienia; public function FasadaRabatow(IntegeridKlienta) { klient = new Klient(idKlienta); rabaty = new Rabat(klient); koszyk = new Koszyk(); zamowienia = new Zamowienia(klient); } public Float rabatIndywidualny() { return klient->getRabatIndywidulany(); } public Float rabatOdZakupowWKoszyku() { return rabat->liczRabat(koszyk->getWartosc()); } public Float getRabatOdWielkosciZamowien() { return rabat->liczRabat(zamowienia->getSume()); } } |
Poniżej prezentujemy jeszcze szkielety klas
Klient, Rabat, Koszyk i Zamowienia. Jak zawsze jest
to jedynie szkielet, nie zawierający wartościowego
kodu, mający na celu jedynie zaprezentowanie
działania wzorca:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
class Klient { private $strImie; private $strNazwisko; private $fltRabat; // ... inne dane o kliencie ... public function __ construct($intIdKlienta) { //pobranie informacji o kliencie } public function getImie() {return $this->strImie; } public function getNazwisko() { return $this->strNazwisko; } public function getRabatIndywidualny() { return $this->fltRabat; } } class Rabat { private $objKlient; public function __construct(Klient $objKlient) { $this->objKlient = $objKlient; } public function liczRabat() { //liczenie rabatu return $fltRabat; } } class Koszyk { public function getProdukty() { // wyciągniecie informacji o produktach w koszyku return $arrKoszyk; } public function dodajProdukt($intId) { // dodanie produktu do koszyka } public function usunProdukt($intId) { // usunięcie produktu z koszyka } public function getWartosc() { // obliczenie wartości produktów w koszyku return $fltWartosc; } } class Zamowienia { private $objKlient; public function __construct(Klient $objKlient) { $this->objKlient = $objKlient; } public function zamow(Koszyk $objKoszyk) { // zamówienie produktów z koszyka } public function getSume() { //oblicz sumę wszystkich zrealizowanych zamówień return $fltSuma; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
public class Klient { private String imie; private String nazwisko; private Float rabat; // ... inne dane o kliencie ... public function Klient(Integer idKlienta) { //pobranie informacji o kliencie } public String getImie() { return imie; } public String getNazwisko() { return nazwisko; } public Float getRabatIndywidualny() { return rabat; } } public class Rabat { private Klient klient; public function __construct(Klient klient) { this.klient = klient; } public Float liczRabat() { //liczenie rabatu return rabat; } } public class Koszyk { public ArrayList<Produkt> getProdukty() { // wyciągniecie informacji o produktach w koszyku return koszyk; } public void dodajProdukt(Integer id) { // dodanie produktu do koszyka } public void usunProdukt(Integer id) { // usunięcie produktu z koszyka } public Float getWartosc() { // obliczenie wartości produktów w koszyku return wartosc; } } public class Zamowienia { private Klient klient; public function_construct(Klient klient) { this.klient = klient; } public void zamow(Koszyk koszyk) { // zamówienie produktów z koszyka } public Float getSume() { //oblicz sumę wszystkich zrealizowanych zamówień return suma; } } |
Jak to działa? Program wszędzie tam, gdzie
potrzeba jest na przykład wartość rabatu od
sumy produktów w koszyku klienta, nie składa
za każdym razem kilku klas, a korzysta z jednej,
FasadaRabatów i z jej metody rabatOdZakupowWKoszyku(). Podsumowując, fasada posłużyła do
zbudowania często używanych metod z klocków
jakimi jest zbiór kilku klas systemu.
Poznałeś już kilka wzorców projektowych. Ich
liczba jest już wystarczająca aby analizować swoje
programy i zastanowić się gdzie i co mogłeś
zrobić lepiej. Warto też zastanowić się jak można
skutecznie połączyć klika wzorców projektowych
w jeden.
Kiedy używać i co nam to daje
Nad zastosowaniem fasady warto zastanowić się wówczas, gdy chcesz obudować złożony system
prostym interfejsem lub w systemie występuje wiele zależności pomiędzy klasami abstrakcyjnymi
a klasami je implementującymi.
Dzięki fasadzie można uniezależnić podsystem i zapewnić jego przenośność. A dokładniej, oddzielić
kod kliencki od komponentów, dostarczając mu jeden (lub klika, ale zawsze mniej niż istnieje komponentów)
interfejs obsługi podsystemu. Sprzyja to łatwiejszemu użyciu. Komponenty zostają o wiele
słabiej powiązane z kodem klienckim, dzięki czemu można je łatwiej podmienić w kodzie fasady, co nie
powinno mieć wpływu na działanie kodu klienckiego.
Pamiętaj jednak że fasada nie blokuje dostępu do komponentów, które obudowuje. W kodzie kliencki
możesz użyć fasady lub bezpośrednio komponentów – w zależności od potrzeby.
Fasada w pigułce
- Wyodrębnij rodziny działań które w systemie
często są wykonywane, -
Działania z tej samej rodziny skomponuj
w metody nowej klasy, - W metodach klasy fasady użyj do wykonania
zaplanowanych działań innych obiektów
systemu.
Może Cię zainteresować:



