Wzorzec Repository – dostęp do bazy

Wzorzec Repozytorium to kolejny sposób na organizację naszego dostępu do bazy danych. To w pełni obiektowy wzorzec, który pozwala nam spełnić wszystkie dobre zasady programowania.

W tym wpisie odwołuję się do przykładów z poprzedniego wpisu o wzorcu Table Data Gateway.

Wzorzec Repozytorium

W poprzednim wzorcu pobieraliśmy i zapisywaliśmy dane. Jeśli programujemy obiektowo chcemy, aby nasze dane istniały w formie obiektów. Powinniśmy zrezygnować z metody addCar($name,$model,$engine) na rzecz metody np. add(Car $object). Same obiekty klasy Car tworzylibyśmy gdzieś indziej. Pojawia się pytanie – gdzie?

Wyobraźmy sobie zakład produkujący auta. W takim zakładzie mamy fabrykę i magazyn. Jest też zarządca, który dostarcza klientom gotowe pojazdy. Jeśli więc chcemy otrzymać nowe auto – zwracamy się do fabryki. Jeśli chcemy pobrać auto z magazynu – zwracamy się do magazyniera.

Prawie tak wygląda wzorzec Repozytorium. Nasz magazynier jest naszym repozytorium. Fabryka z kolei zajmuje się montażem. Może się okazać, że magazynier ma auto w częściach i potrzebuje je zmontować przed wydaniem go nam (klientowi). Wtedy też zwraca się do fabryki przekazując swoje części z magazynu.

Repozytorium (zarządca) łączy trzy rzeczy. Fabrykę produkującą pojazdy. Magazyn części i pojazdów oraz klienta zamawiającego samochód.

Przekładając to z ludzkiego na PHP zacznijmy od samego auta:

class Car {
   public $name, $model, $engine;
}

Fabryka będzie tworzyć nasze obiekty na podstawie części:

class CarFactory {
   public function makeCar($name,$model,$engine) { ... }
}

Samo repozytorium za to służy jedynie do zapisania lub pobrania samochodu. Wewnątrz będzie korzystać z wcześniejszej klasy Cars czyli naszego Table Data Gateway:

class CarRepository {

   public function storeCar(Car $car) {
      CarsStorage::addCar($car->name, $car->model, $car->engine);
   }

   public function findCar($name) {
      $car = CarsStorage::getByName($name);
      $carObject = CarFactory::makeCar($car["name"],$car["model"],$car["engine"]);
      return $carObject;
   }

}

Dla uproszczenia pominąłem wstrzykiwanie zależności (dependency injection), które warto tutaj zastosować. Repozytorium powinno otrzymać zarówno fabrykę jak i naszą Table Data Gateway.

Zalety wzorca Repozytorium

Przede wszystkim sytuacja jest przejrzysta. Osobne klasy odpowiadają za komunikację z bazą, tworzenie obiektów i zarządzanie nimi. Klient nie musi nic wiedzieć o bazie danych. Wręcz nie powinien! Komunikuje się tylko z fabryką i z repozytorium. Z drugiej strony magazyn nie wie nic o obiektach biznesowych. Przekazuje nam tylko części.

Testowanie jest dość proste. Osobno testujemy fabrykę. Osobne testy piszemy dla repozytorium. Same obiekty też możemy testować gdyby zawierały jakąś logikę (np. samokontrolę itp).

Jeśli zamiast konkretnych klas zaprojektujemy naszą fabrykę i magazyn jako interfejsy to sytuacja będzie jeszcze lepsza. Możemy użyć innego magazynu. Tak samo fabryka może być dowolnym obiektem, który tylko produkuje obiekty biznesowe.

Kiedy warto używać

Rozdzielenie logiki biznesowej i implementacji daje nam czysty kod. Jak zawsze jednak warto podchodzić do wzorca z rozsądkiem. W małej aplikacji gdzie obiekty wprost reprezentują bazę wzorzec Repozytorium może być zbyt skomplikowany. Czasem prościej jest zastosować nie w pełni obiektowe rozwiązanie czyli Table Data Gateway. Dopiero gdy nasz kod rośnie, jest zarządzany przez wielu programistów a aplikacja jest złożona – warto korzystać z wzorców takich jak Repozytorium.

Warto przeczytać bardzo dobry artykuł o wzorcu Repository. Autor pokazuje go nam na przykładzie w PHP. Przy okazji buduje kod w oparciu o metodykę TDD (Test Driven Developement).

Dodaj komentarz

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