Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Wzorzec fabryki
Forum PHP.pl > Forum > PHP > Object-oriented programming
Orzeszekk
Pytanie do mądrzejszych ode mnie forumowiczów.

Mam klase np. abstractMessage która jest szkieletem zapisujacym message do bazy danych.

następne z klasy abstractMessage tworze klasy pochodne np SMSMessage, EmailMessage.
Rodzaj wiadomosci przechowuje w polu $type obiektu abstractMessage, dzieki czemu wiadomo czy to SMSMessage, i EmailMessage.

Potrzebuje wzorca fabryki (metody wytwórczej?), tylko poprawnego. Teraz bym to zrobił tak:

  1. class abstractMessage{
  2. public static function load($databaseRow)
  3. {
  4. [....]
  5. switch ($databaseRow->type)
  6. {
  7. case TYPE_SMS_MESSAGE: return new SmsMessage($databaseRow); break;
  8. case TYPE_EMAIL_MESSAGE: return new EmailMessage($databaseRow); break;
  9. }
  10. }
  11. }

jednak takie rozwiązanie jest podobno do kitu ponieważ w przypadku jeżeli powstaną nowe typy dziedziczące po abstractMessage to będe musiał zmodyfikować ten switch tworzący obiekty, a w ten sposob zlamie zasade otwarte-zamknięte - zamiast rozszerzać klasę dodajac metody modyfikuję istniejący kod w celu rozszerzenia funkcjonalności.

No a jeżeli nie utworze odpowiedniego typu (SMSMessage, EmailMessage) to nie będę mógł użyć ich specyficznych metod.

Więc jak to poprawnie rozwiązać? Chcę rozwiązania na maksa poprawnego z dobrymi praktykami programistycznymi, bo już dostałem niedawno durszlakiem pełnym kodu spagetti mocno w głowę i chcę tego uniknąć smile.gif
Sephirus
Nie do końca Cię rozumiem ale mogę podpowiedzieć:

Pamiętaj że zapis:

  1. new SmsMessage($databaseRow);


Jest równoważny z:

  1. $className = 'SmsMessage';
  2.  
  3. new $className($databaseRow);


wink.gif

I cytat z jakiegoś kodu dotyczącego fabryki:

  1. <?php
  2. public function make( $className )
  3. {
  4. return new $className();
  5. }
  6. ?>


tongue.gif
Orzeszekk
No to juz odchodzi mi koniecznosc pisania new nazwa_klasy. ale w dalszym ciagu musze dodawac do metody wytwórczej kolejne klasy zeby wiedzialo jakich nazw klasy tworzyc.

Nie da sie jakos automatycznie tego , zamknąć w klasie pochodnej? biggrin.gif w "clean code" pisalo ze taki kod gdzie rozrasta sie switch jest do kitu tongue.gif
mortus
  1. class abstractMessage {
  2. /* ... */
  3. public static function load($databaseRow) {
  4. $messageType = $databaseRow->type;
  5. $className = ucfirst(strtolower(substr($messageType, 6, strpos('_', $messageType, 6)-1))) . 'Message';
  6. return new $className($databaseRow);
  7. }


Oczywiście to wtedy, jeśli $databaseRow->type przechowuje nazwy stałych, to jest TYPE_SMS_MESSAGE, czy TYPE_EMAIL_MESSAGE.
Pisane z palca, ale na oko widać, że metodę można "udoskonalić".

Wypada również sprawdzić, czy klasa o nazwie zawartej w zmiennej $className istnieje i jest załadowana, a dopiero później spróbować utworzyć obiekt tej klasy a potem go zwrócić. W przypadku niepowodzenia można rzucić wyjątek.
LSM
Zawsze musi istnieć informacja o tym jaka klasa ma być użyta. To wiadome. Teraz od nas zależy kiedy tą informacje wykorzystamy - czy na poziomie kontrolera i tu:
Kod
class Controller {

$CommunicatorWithClients = new $NameFromPost();
$CommunicatorWithClients->sendMessage();
}

czy na poziomie fabryki, czy innego sposobu jak odrębnej klasy która wybiera nam klasę do zbudowania obiektu na zasadzie strategii. Temat o tyle śliski, że dosyć niejednoznaczny - który sposób wybrać. Sam zawsze mam z tym problemy ale tylko dlatego, że myślę o elastyczności zbyt wcześnie. Zależy to od innych rzeczy, które znajdują się w kodzie. Jeśli wiesz, że będziesz rozszerzać klasę komunikacji dobrze użyć Strategii w tym przypadku jak na moje oko ;-). W switchach nie ma nic złego dopóki nie zaczynają nam przeszkadzać. Dwa case'y w switch to nie tragedia, ja bym sie tym narazie nie przejmował. Nazwij tego switch'a jako funkcje TwinPeaks() i już ;-) .

Pozdrawiam.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.