Magazyn T3
newsy, felietony, testy i tutoriale



Internet Maker

11/09/2008

Wzorce projektowe – fasada

Więcej artykułów autorstwa »
Napisane przez: Marcin Staniszczak
Tagi:
48-wzorce_projektowe_-_fasada.jpg

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ć:

  1. Wzorce projektowe – proxy
  2. Wzorce projektowe – strategia
  3. Wzorce projektowe – stan


O autorze

Marcin Staniszczak





0 komentarzy


Skomentuj pierwszy!


Zostaw odpowiedź

Twój adres nie zostanie opublikowany. Wymagane pola są oznaczone *

*

Możesz używać tych tagów i atrybutów HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">