Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Styl pisania kodu obiektowego korzystając z MVC
Forum PHP.pl > Forum > PHP > Object-oriented programming
Luneth
Witam, załóżmy, że piszę sobie framework w MVC, wymyśliłem sobie, że zrobię moduł newsów w oparciu o ten wzorzec projektowy, np:
Cytat
1. Kontroler rozszerza Widok, tworzy obiekt modelu, oraz korzystając z konstruktora rodzica przekazuje mu instancję tegoż modelu;
2. Kontroler wybiera jedną z dwóch metod: ShowSingleNews lub ShowNewsList, obie są metodami widoku - pobierają z modelu odpowiednio wybrane przez siebie dane, metodą widoku przekształcają timestampy na ludzkie daty, umieszczają element tablicy danych pobranych z MySQL do kodu html, wybierając jedną z trzech metod widoku: showPinned, showExtended, showOnList.
3. Wybrana przez kontroler metoda zwraca kod html jako string, który jest wyświetlany jako zawartość całej strony przez metodę widoku Display ( $this->ShowSingleNews() ) lub Display ( $this->ShowNewsList() )


Teraz przedstawienie problematyki: ogólnie filozofia programowania obiektowego opiera się na tym, aby obiekty traktować jako przedmioty, a atrybuty i metody jako ich własności i czynności, które mogą wykonać. Zgodnie z tym powinienem ponadto utworzyć sobie klasę NewsItem (i umieścić ją gdzieś osobno, bo nie wiem do czego miałbym ją przydzielić w MVC), miałaby ona atrybuty zgodne z polami w bazie danych a metody takie jak Show (czyli kod html - widok?), oraz gettery i settery. Ewentualnie można by pominąć to Show a zastosować właśnie same settery i gettery. Ale nowa klasa, nowy obiekt tylko po to, aby posiadał same settery i gettery jedynie po to, by w klasie News móc najpierw utworzyć pętlą tablicę obiektów, a następnie drugą pętlą wyświetlić zawartość obiektów? Poza ładną tablicą i faktycznym, abstrakcyjnym przedstawieniem struktury Newsów, tracimy na wydajności no i trochę w MVC sobie bałaganimy. Kończę swój wywód i czekam na Wasze odpowiedzi smile.gif
wookieb
Cytat(Luneth @ 9.08.2010, 00:29:36 ) *
aby obiekty traktować jako przedmioty, a atrybuty i metody jako ich własności i czynności, które mogą wykonać.

To, że w definicjach jest napisane, że obiekty służa do lepszego opisywania rzeczywistości (a nie wszystko jest przedmiotem) wcale nie znaczy, że musisz ładować obiekty tam gdzie się da.
To, że samochód osobowy z definicji służy głównie do przewożenia osób to nie znaczy, że nie przewieziesz z tyłu 100kg kabaczek.

Nie ma sensu definiować obiektu dla każdego typu danych bo faktycznie wydajność spada a prawie nic dzięki temu nie zyskujemy więc nadal swobodnie można posługiwać się tablicami. Kontroler przekazuje je do widoku a widok robi z tym co chce.
Zyx
^^^ Kontroler nie przekazuje danych z modelu do widoku w MVC.

Luneth -> to, co piszesz, nazywa się ORM i służy do nieco innych celów. Jeśli zastąpisz ORM-em warstwę modelu, przestanie to być model, który z założenia ma być niezależny od źródła danych. U mnie model komunikuje się ze światem zewnętrznym przy pomocy najzwyklejszych tablic, zaś ewentualnie dopiero pod nim siedzi ORM, i to nie zawsze.
Luneth
wookieweb: dokładnie tak samo myślę, chociaż kusi mnie taka dokładna obiektowość, może dlatego, że jestem trochę pedantyczny w takich sprawach smile.gif Btw, początkowo o MVC też myślałem jak Ty, że kontroler bierze dane z modelu i przekazuje je do widoku, ale na tym się traci: jeśli zechcę dorobić parę widoków lub zmienić format wyświetlania (z html na pdf np) to nie grzebię w modelu (bo po co mi stronicowanie w pdf? nie uwzględniam tego po prostu w widoku) a tak po prostu robię widok dla pdf i koniec smile.gif

Zyx: Model ma być niezależny, bo przewidujemy różnorodność źródeł danych i ich format (różne bazy danych, pliki, etc) ? Swoją drogą nie miałem zamiaru zastępować modelu taką klasa Newsa, u mnie miałoby to działać tak: Dane z modelu -> (pętla tworząca tablicę obiektów)NewsItem -> (pętla tworząca kod html tejże listy używając obiektów NewsItem)NewsList -> RenderPage()

Cytat
U mnie model komunikuje się ze światem zewnętrznym przy pomocy najzwyklejszych tablic, zaś ewentualnie dopiero pod nim siedzi ORM, i to nie zawsze.


Przy pomocy najzwyklejszych tablic - czy masz na myśli, że model po prostu zwraca tablice zwykłe, lub obiekty PDO?)
Zyx
Jeśli mówimy o MVC, to tak. Model możemy opisać następująco:
- Interfejs jest niezależny od źródła danych
- Interfejs jest definiowany tak, by pasował do rodzaju reprezentowanych danych, czyli np. jeśli mamy newsy, wtedy będzie on pozwalał na tworzenie, edycję, usuwanie, komentowanie itd. Jeśli zaś ma reprezentować np. wirtualny system plików, wtedy posiada on funkcje do zarządzania tymi plikami.

Niedawno doszedłem do wniosku, że w typowej aplikacji znalazłoby się dużo rzeczy, które byłyby modelem, a nie znajdowałyby się w bazie danych. Weźmy np. menedżera nawigacji. W ZF masz do tego osobny, specjalistyczny komponent: Zend_Navigation. A przecież tak naprawdę jedyne, co on robi, to udostępnia pewne dane... widokom, czyli powinien być modelem.

Odnośnie drugiej części -> powtarzam: to, co piszesz, nazywa się ORM-em i są do tego gotowe biblioteki (np. Doctrine). Samodzielne pisanie to strata czasu. Pomysł z tworzeniem w pętli mnóstwa obiektów jest średnio ciekawy z powodów wydajnościowych. Jeśli nie potrzebujesz nic specjalnego w tych obiektach, lepiej jest zrzucić wszystko od razu do tablicy i posłać w świat. Obiektów PDO nie udostępniam poza modelem z powodu tego, co napisałem wcześniej: model powinien być niezależny od źródła danych, tj. powinien ukrywać fakt, że komunikuje się akurat z bazą.
erix
Cytat
Odnośnie drugiej części -> powtarzam: to, co piszesz, nazywa się ORM-em i są do tego gotowe biblioteki (np. Doctrine). Samodzielne pisanie to strata czasu.

Czy ja wiem...? Doctrine/Propel są strasznie zasobożerne, polemizowałbym.
Luneth
Zyx, utwierdziłeś mnie w przekonaniu że to faktycznie poza jakąś tam estetyką zalet żadnych nie ma a przewaga wad powinna zniechęcić każdego do tego pomysłu smile.gif
Jedna kwestia, News_Model z metodą dodaj, czyli ten model mógłby być wykorzystywany przez np jakiś Panel Administracyjny i zawierać jednocześnie inne metody, np wyświetlania listy, która używana w Panelu nie będzie? Czy lepiej robić osobne modele dla zarządzania, osobne do wyświetlania?
Zyx
erix -> Doctrine 2 + APC = hardkorowa wydajność.

Luneth -> a czemu nie? Ja osobiście robię tak, że mam zbiór interfejsów do różnych typowych czynności i model informuje, że potrafi np. dodawać coś, implementując interfejs odpowiedzialny za dodawanie. W ten sposób mogę mieć ogólny widok do wszystkiego i łączyć go z dowolnym modelem.
Luneth
Zyx, czy mógłbym liczyć na dokładniejsze przedstawienie (np pseudokodem) zastosowania w praktyce tego co napisałeś? smile.gif
smentek
Cytat(Luneth @ 9.08.2010, 00:29:36 ) *
ogólnie filozofia programowania obiektowego opiera się na tym, aby obiekty traktować jako przedmioty, a atrybuty i metody jako ich własności i czynności, które mogą wykonać.


Nieprawda Luneth.
To co opisujesz to nie jest żadna filozofia, a już na pewno nie jest to filozofia programowania obiektowego.

Lepiej było by powiedzieć:

"Filozofią programowania zorientowanego na obiekty jest zakodowanie (zamodelowanie) fragmentów jakiejś tam rzeczywistości w taki sposób aby tworzone obiekty uosabiały jakieś tam byty a metody tych że obiektów były wiadomościami, które mówią im co mają robić. ". Te obiekty mogą nie mieć nic w spólnego z rzeczywistymi bytami takimi jak pralka czy samochód mogą być całkiem abstrakcyjne. Ważne jest aby to co było wewnątrz obiektów w miarę możliwości nie wychodziło na wierzch.

Wiem że nie brzmi to fajnie ale przecież filozofia nie była by filozofią gdyby była truizmem.


Crozin
@smentek: Może to już czepialstwo, ale... chyba powiedziałeś to samo tylko bardziej "akademicko".
smentek
Ha! @crozin Może w dużej części tak ale nie do końca. Dzielimy włos na czworo ale muszę odpowiedzić smile.gif
Różnice:
- Obiekt nie musi być fizycznym bytem jak było to sugerowane wcześniej.
- Brak informacji o enkapsulacji danych w obiektach (a to jest chyba samo sedno)

I nie mówie wcale, że moja definicja jest idealna ale uważam ze jest lepsza winksmiley.jpg.
dariuszp
Cytat
Teraz przedstawienie problematyki: ogólnie filozofia programowania obiektowego opiera się na tym, aby obiekty traktować jako przedmioty, a atrybuty i metody jako ich własności i czynności, które mogą wykonać. Zgodnie z tym powinienem ponadto utworzyć sobie klasę NewsItem (i umieścić ją gdzieś osobno, bo nie wiem do czego miałbym ją przydzielić w MVC), miałaby ona atrybuty zgodne z polami w bazie danych a metody takie jak Show (czyli kod html - widok?), oraz gettery i settery. Ewentualnie można by pominąć to Show a zastosować właśnie same settery i gettery. Ale nowa klasa, nowy obiekt tylko po to, aby posiadał same settery i gettery jedynie po to, by w klasie News móc najpierw utworzyć pętlą tablicę obiektów, a następnie drugą pętlą wyświetlić zawartość obiektów? Poza ładną tablicą i faktycznym, abstrakcyjnym przedstawieniem struktury Newsów, tracimy na wydajności no i trochę w MVC sobie bałaganimy. Kończę swój wywód i czekam na Wasze odpowiedzi smile.gif


Mieszasz wg mnie za bardzo. NewsItem powinien być elementem kontrolera. Ten powinien mieć dostęp do modelu przez jakiś interfejs (najczęściej za model robi baza danych). Świetnym wzorcem który przypadł mi do gustu jest Data Mapper. Poczytaj. Odwzorowanie źródeł danych w postaci obiektów daje ogromną zaletę. Programista który na tego typu mapperach operuje nie musi wiedzieć czy dane trafiają do bazy danych, pliku, zewnętrznego serwera czy na email jakiegoś trolla który potem będzie bluzgał że mu skrzynkę zaśmiecasz.
Odpowiednio przygotowane dane (przygotować je może jakiś adapter bądź sama klasa NewsItem) powinny trafić do widoku. Widok ma się nimi zaopiekować i w odpowiednim miejscu wyświetlić.
To czy będziesz operował na danych tablicowych czy obiektach to już kwestia wyznania. Podejście gdzie WSZYSTKO jest obiektem w PHP wg mnie jest cokolwiek chore. Dane powinny płynąć z jednego miejsca do drugiego w postaci tablic, ciągów znaków i obiektów w zależności od potrzeb i możliwości. Na pewno nie generował bym 200 obiektów tylko po to by tak pobrane dane iterować i umieszczać w szablonie.

Kod
dokładnie tak samo myślę, chociaż kusi mnie taka dokładna obiektowość, może dlatego, że jestem trochę pedantyczny w takich sprawach


Wiesz, mnie kusi by czasami przywalić komuś w gębę. Wykonanie tej czynności na pewno sprawiło by mi przyjemność ale skutki mogły by być różne. Sam widziałem absurd obiektowości u gościa który nawet ciągi znaków zamykał w obiektach (stworzył sobie klasę string z użyciem invoke(), toString() i innymi metodami magicznymi które są dla nas dostępne (invoke() chyba od php5.3). Jak to profilowałem to złapałem się za głowę.

Kod
Model ma być niezależny, bo przewidujemy różnorodność źródeł danych i ich format (różne bazy danych, pliki, etc) ? Swoją drogą nie miałem zamiaru zastępować modelu taką klasa Newsa, u mnie miałoby to działać tak: Dane z modelu -> (pętla tworząca tablicę obiektów)NewsItem ->  (pętla tworząca kod html tejże listy używając obiektów NewsItem)NewsList -> RenderPage()


Jak mówiłem. Skoro przewidujesz różne źródła danych to zmappuj je. Troszkę się opiszesz przy mapperach ale potem pójdzie gładko. Właściwie przy bazie danych szybko załatwisz sprawę. Po zbudowaniu mappera, rozszerzając go podasz tylko specyficzne pola dla tabel + nadasz jakieś filtry i tyle. Potem tylko:

$news_item->save($mapper);
$news_item2->save($mapper);
$news_item3 = $mapper->load_by_id($id);
$news_item3->delete($mapper);

Użytkownik Twojego kodu nawet nie musi mieć pojęcia co się stało z danymi po zapisaniu i gdzie one są.

Kod
Obiekt nie musi być fizycznym bytem jak było to sugerowane wcześniej.


Hmmm... ciekawość :-) Jakie nie-fizyczny byt proponował byś ?

Pozadrawiam.

Luneth, a co do pytania w temacie:
Jak rozdrabniać moduły ? NIE ROZDRABNIAĆ ICH tongue.gif O ile obiekt odpowiedzialny za obsługę bazy danych, plików czy czegokolwiek innego "od środka" powinien mieć ziarnisty interfejs (dużo metod od różnych akcji) o tyle sam interfejs obiektu czyli to co jest dostępne użytkownikowi Twojego kodu (i Tobie) powinien być ograniczony do minimum. Samo zaś traktowanie wszystkiego jako obiekt jest moim zdaniem błędne. Jeżeli potrzebny Ci do czegoś obiekt to go utwórz. Ale nie ma sensu np pobrać dane np z bazy, upakować je w 200 obiektów a następnie wyświetlić. O wiele lepiej jest przekazać tablicę. Chyba że masz jeszcze coś skomplikowanego robić na każdym z tych 200 rekordów bazy.


Luneth
Wow... nie spodziewałem się wznowienia tematu po takim czasie. Więc na początek tak:

@smentek - wybacz, że to powiem, ale Twój nick do Ciebie idealnie pasuje. To czepianie się jest smętne. Bardzo smętne. I w tym przypadku w 100% zgadzam się z Crozinem. Nic do tematu nie wniosłeś oprócz swojej jakiejś tam definicji, która - okej, może coś więcej tam uściśla, ale w gruncie rzeczy NIC do tematu nie wniosła konstruktywnego.

@dariuszp - nie wiedziałem, że tak skrajnie zabrzmiałem. Nie kusiło mnie nigdy pisanie funkcji i bibliotek dostarczanych wraz z PHP w myśl idealnego kopiowania ich działania. A co do dostępu modelu do kontrolera to możemy znowu się kłócić, że kontroler kojarzy model z widokiem a nie, że ma do niego dostęp. Bo w MVC kontroler jedynie te rzeczy ze sobą kojarzy. Sam fakt, że robienie obiektu ze zwykłej tablicy, żeby w niej trzymać same dane jest skrajny i posiada dużo wad - powiedzieli to już ludzie wypowiadający się na początku. Jak się zapewne domyślasz nigdy nie wprowadziłem tego pomysłu w życie. Chętnie poczytam o wzorcu data mapper, szczerze to jedyna informacja, która coś wnosi do tematu biggrin.gif

Cytat
Odwzorowanie źródeł danych w postaci obiektów daje ogromną zaletę. Programista który na tego typu mapperach operuje nie musi wiedzieć czy dane trafiają do bazy danych, pliku, zewnętrznego serwera czy na email jakiegoś trolla który potem będzie bluzgał że mu skrzynkę zaśmiecasz.

Zajeżdża trochę tym, czym jest po prostu model winksmiley.jpg
dariuszp
Moja wina. Niewłaściwe słowa użyłem. Ale wiesz o co mi chodzi.

Co do mappera i ostatniego cytatu to owszem - model. Chodziło mi o samo podejście. Z odrobiną wysiłku posunąłem się do tego że podaje dla skryptu dane dostępu do bazy danych a on generuje mi kod PHP (mappery i obiekty danych) dla tabel. Także wykonuje za mnie jakieś 80% pracy. Po wszystkim moim zadaniem jest tylko uzupełnić poszczególne mappery o metody specjalne które robią coś oprócz podstawowych akcji. Jedynym ograniczeniem dla mnie było to by zachować pewien styl nazewnictwa.
Potem operując na użytkownikach, ładuje odpowiedni mapper i się bawię. A ma to o tyle fajną zaletę że wystarczy że zmienię jedną linijkę programu i np dane użytkowników nie będą zapisywane do bazy tylko będą pobierane/zapisywane na zewnętrznym serwerze czy w plikach.
Dlatego szczerze polecam tą metodę.

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.