zzeus
19.12.2008, 19:01:26
Czytałem kilka podobnych wątków ale nigdzie nie znalazłem jednoznacznej odpowiedzi. Załóżmy że mamy zdjęcia, napisaliśmy sobie klasę Zdjecie która obsługuje zdjęcia. Jak jednak pobrać 100 zdjęć ? Stworzyć funkcję która pobiera pobiera z bazy info o tych zdjęciach i zwrócić jako tablicę, stworzyć funkcję która zwróci tablicę 100 obiektów typu zdjęcie, stworzyć metodę w klasie Zdjecie która pobierze z bazy i zwróci w postaci tablicy dane o 100 zdjęciach ? Jak rozwiązujecie taki problem ?
Pozdrawiam
erix
19.12.2008, 20:35:08
Cytat
Jak rozwiązujecie taki problem ?
Możesz wykorzystać tu interfejs
Iterator. Nie męczysz za bardzo pamięci, a dodatkowo wygodniej.
zzeus
19.12.2008, 21:13:08
Chodzi mi o coś takiego, że czasami potrzebuje pobrać 100 zdjęć, czasami 20 a czasami 3. Dodatkowo nie zawsze potrzebuje wszystkie dane o zdjęciu, np. czasami nie potrzebuje wiedzieć jakie ma wymiary. Jednocześnie chciałbym aby dane o zdjęciu były zawsze prezentowany w ten sam sposób. Więc jak to uzyskać ? Napisać 3 funkcje, które pobiorą z bazy za pomocą odpowiedniego zapytania interesujące mnie dane, i na ich podstawie tworzyć obiekt typu zdjęcie, który sobie ustawi tylko te pola dla których dostanie wartości ?
No i czy w przypadku kiedy pobieram te dane o iluś tam zdjęciach tylko po to aby je wyświetlić na stronce, to czy opłaca się tworzyć np. 100 obiektów typu zdjęcie tylko po to aby za chwilę zwróciły one dane w postaci tablicy ? Czy od razu ładować poprostu dane do tablicy bez tworzenia obiektu i przekazać do smarty ?
Pozdrawiam
erix
19.12.2008, 21:32:24
Cytat
Napisać 3 funkcje, które pobiorą z bazy za pomocą odpowiedniego zapytania interesujące mnie dane, i na ich podstawie tworzyć obiekt typu zdjęcie, który sobie ustawi tylko te pola dla których dostanie wartości ?
Przy konstruowaniu klasy podajesz w tablicy, które dane chcesz uzyskać.
Cytat
No i czy w przypadku kiedy pobieram te dane o iluś tam zdjęciach tylko po to aby je wyświetlić na stronce, to czy opłaca się tworzyć np. 100 obiektów typu zdjęcie tylko po to aby za chwilę zwróciły one dane w postaci tablicy ?
A czy przeczytałeś mojego poprzedniego posta?
zzeus
19.12.2008, 22:06:27
A mógłbyś podać jakiś przykład, bo chyba nie do końca rozumiem.
Tworzę sobie iterator, nakazuje mu pobrać 12 zdjęć
<?php
$_objPhoto = new Photo();
$iterator = new Iterator($_objPhoto->getPhoto(), 12);
while($photo = $iterator->next())
{
$_arrPhotos[] = $photo;
}
?>
Czy to miałoby wyglądać mniej więcej tak ?
W takim przypadku wykonuje 12 zapytań do bazy danych, i tworzę 12 obiektów klasy Photo. Chyba że się mylę ?
W przypadku funkcji mogę pobrać 12 zdjęć w jednym zapytaniu i zwrócić w postaci tablicy, takiej samej jaką tutaj otrzymam.
karmer
19.12.2008, 22:16:51
Witam,
stwórz sobie klasę "galeria", która będzie miała prywatną tablicę obiektów "photo". W klasie "galeria" umieść metody operujące na zbiorze zdjęć, np. wczytywanie zdjęć do obiektu galerii, pobieranie z niej zdjęć i inne operacje, które sobie wymarzysz.
Pozdrawiam
zzeus
19.12.2008, 22:30:22
Cytat(karmer @ 19.12.2008, 22:16:51 )

Witam,
stwórz sobie klasę "galeria", która będzie miała prywatną tablicę obiektów "photo". W klasie "galeria" umieść metody operujące na zbiorze zdjęć, np. wczytywanie zdjęć do obiektu galerii, pobieranie z niej zdjęć i inne operacje, które sobie wymarzysz.
Pozdrawiam
To chyba jest okrojona wersja Iteratora
erix
19.12.2008, 22:32:35
<?php
class klasa implements Iterator{
//
}
$c = new klasa;
foreach($c as $obrazek){
}
?>
Odpowiednie funkcje, których powinieneś użyć w klasie, są opisane w Sieci, rusz się.
karmer
19.12.2008, 22:45:01
Klasa galerii może dla Twojej wygody implementować interfejs Iteratora. Zrobienie jednak z galerii "czarnej skrzynki" byłoby dla mnie bardziej wygodne. Udostępniasz metody "galerii" na zewnątrz (musisz przemyśleć jakie moetody byłyby przydatne dla użytkownika takiej klasy) a resztę zamykasz wewnątrz. Potem możesz modyfikować 'bebechy' takiej klasy bez zmiany jej interfejsu. Bo np. gdybyś chciał z jakichkolwiek powodów zrezygnować z interfejsu iteratora to co wtedy? Ktoś kto umieścił Twoją klasę galerii we własnym projekcie musiałby zmieniać swój kod.
erix
19.12.2008, 23:33:56
Cytat
Bo np. gdybyś chciał z jakichkolwiek powodów zrezygnować z interfejsu iteratora to co wtedy?
A niby czemu miałby rezygnować? Masz na myśli jakiś konkretny powód?
karmer
19.12.2008, 23:53:40
Nie miałem na myśli konkretnego przypadku. Raczej dla zachowanie idei hermetyzacji i przenośności. Teoretycznie interfejs iteratora też może się kiedyś zmienić, albo może być zastąpiony innym rozwiązaniem. Wiem, że to mało prawdopodobne :-). W/g mnie klasa galerii z udostępnionym iteratorem byłaby raczej "obiektem kontenera zdjęć" a nie obiektem galerii. I mogłaby wtedy posłużyć jako rdzeń galerii.
erix
20.12.2008, 00:43:16
To może w ogóle nie używajmy SPL? Bez przesady, bardziej prawdopodobne, że zostaną dodane nowe interfejsy do biblioteki niż usunięte.
Nie używaj wyjątków, bo też zostaną zmienione. Najbardziej mnie boli w przypadku projektowania aplikacji dla PHP5 takie oporne korzystanie z SPL, no nie mogę tego znieść. A potrafią odwalić kawał dobrej roboty (choćby iteracja rekursywna - coś, co klepało się dziesiątkami linijek sprowadza się do max kilku i do tego z dużo większą wydajnością).
Wyjdźmy z ciemnogrodu PHP4.
zzeus
20.12.2008, 12:10:21
Poszukałem, poczytałem i chyba mam rozwiązanie.
Klasa Kolekcja, która będzie służyła jako swego rodzaju tablica do przechowywania obiektów. Klasa IteratorKolekcji która będzie służyć do iterowania kolekcji przekazanej jako parametr. Będzie można tworzyć potomków klasy Kolekcja precyzując typ obiektów które można będzie przechowywać. Do tego wzorzec Factory dla klasy Zdjecie, czyli klasa FactoryZdjecie która będzie zawierała statyczne metody pobierające odpowiednie dane z bazy danych, tworzyła na ich podstawie obiekty i nimi wypełniała kolekcję. W klasie Kolekcja zaimplementowana leniwa konkretyzacja, która będzie wybierała odpowiednią metodę z FactoryZdjecie.
Co o tym myślicie ?
Pozdrawiam
Cysiaczek
20.12.2008, 12:53:31
Nie rozumiem, dlaczego chcesz rozdzielić kolekcję od klasy służącej do jej przeglądania? Tu akurat klasa kolekcji implementująca Iterator jest idealnym rozwiązaniem. Do tego kolekcja może mieć metody getAll(), getNumberOfPhotos($nb), findById() itp. Każdy załadowany obiekt powinien być umieszczony w kolekcji, aby następne odwołanie do niego nie powinno skutkować kolejnym zapytaniem do bazy. Lepiej zatem używać kolekcji od razu, a fabrykę umieścić w jej wnętrzu.
<?php
$c=new PhotoGallery();
$photo=$c->findById(1);
$photo2=$c->findById(2);
$c2=$c->getSelectedPhotos(); // np może zwracać kolejną kolekcję :)
?>
Pozdrawiam
zzeus
20.12.2008, 13:03:17
Takie rozwiązanie było akurat opisane w książce z której korzystam, ale po głębszej analizie doszedłem do wniosku że faktycznie nie ma potrzeby rozdzielania kolekcji od klasy która będzie ją iterować. Ale co do umieszczenia fabryki we wnętrzu kolekcji to nie bardzo wiem o co chodzi.
Pozdrawiam
Cysiaczek
20.12.2008, 13:49:08
Możesz rozdzielić wszystko. Pytanie tylko, czy poniesiony koszt Ci się zwróci?
W teorii dobrym rozwiązaniem jest:
Gallery
PhotoCollection
PhotoFactory
Photo
phpion
20.12.2008, 13:52:39
Cytat(Cysiaczek @ 20.12.2008, 15:49:08 )

Gallery
PhotoCollection
Jaka jest różnica (teoretyczna) między tymi dwoma klasami?
zzeus
20.12.2008, 13:55:11
No więc robię tak:
Photo - klasa przechowująca dane o zdjęciu i posiadająca metody operujące w bazie danych jeśli chodzi o jedno zdjęcie
PhotoCollection - rozszerzenie Collection, zaimplementowana leniwa konkretyzacja i iterator
PhotoFactory - statyczne metody pobierające z bazy danych zdjęcia o określonych parametrach (zdjęcia danego użytkownika, zdjęcia z danej kategorii)
To tyle, jak chodzi o mój pomysł. Co można zmienić aby było lepiej ?
Do czego miałaby służyć klasa Gallery ?
Pozdrawiam
Cysiaczek
20.12.2008, 15:20:28
Jako interfejs - nakładka na wymienione przez Ciebie obiekty.
zzeus
20.12.2008, 15:50:26
Cytat(Cysiaczek @ 20.12.2008, 15:20:28 )

Jako interfejs - nakładka na wymienione przez Ciebie obiekty.
Możesz coś więcej napisać ? Jak by to wyglądało ?
Pozdrawiam
Cysiaczek
20.12.2008, 17:01:04
PhotoCollection to po prostu obiekt kolekcji z podstawowymi metodami add, remove, get. Gallery w tym modelu to taki punkt dostępu do funkcji - żeby ich w ciele akcji nie pisać, tylko wywołać.
<?php
$g=new Gallery();
$g->getFilesCreatedBefore($time);
$g->getPhoto(1) // szuka w kolekcji
$g->findPattern('*.jpg');
?>
itp.
Tylko jak pisałem - nie zawsze trzeba tak dużo abstrakcji robić, bo jest to nieopłacalne, jeśli wykonujemy np tylko podstawowe operacje na plikach czy wpisach w bazie.
Pozdrawiam
zzeus
21.12.2008, 10:43:28
ok, mam już napisane klasy:
Collection
CollectionPhoto
Photo
PhotoFactory
Mam jednak mały problem, w klasie Collection jest metoda
<?php
setLoadCallback($funkcja, $obiektLubKlasa)
?>
Metoda ta korzysta z call_user_func(), i obecnie służy do podawania metody którą należy wywołać z photoFactory aby wypełnić kolekcję (można też korzystać w inny sposób ale to teraz nie ważne). Jednak metody w photoFactory mają różną liczbę parametrów z którymi je wywołuje, i nie wiem zabardzo jak zmodyfikować setLoadCallback żeby przekazywać różną liczbę parametrów. Bo pisanie dla każdej metody z photoFactory odpowiadającej jej metody setLoad... chyba mija się z celem ?
Pozdrawiam
Crozin
21.12.2008, 11:23:10
Użycie
call_user_func_array" title="Zobacz w manualu PHP" target="_manual umożliwia Ci podanie w niej listy parametrów w tablicy (a przez docelową metodę/funkcje odczytanie tego "normalnie").
W setLocalCallback tworzysz zmienną ilość parametrów, zbierasz je
func_get_args" title="Zobacz w manualu PHP" target="_manual, dwa pierwsze indeksy (0, 1) to $funkcja, $obiektLubKlasa. Następnie
array_slice" title="Zobacz w manualu PHP" target="_manualm usuwasz je i pozostałe elementy tablicy przekazujesz jako 2-gi param call_..._array()
zzeus
21.12.2008, 11:30:35
Chyba prościej będzie poprzez call_user_func_array() ?
Crozin
21.12.2008, 11:33:39
No, ale przecież to napisałem
Cysiaczek
21.12.2008, 11:41:10
No nie - użyłeś call_user_func()/
zzeus
21.12.2008, 11:46:06
Cytat(Cysiaczek @ 21.12.2008, 11:41:10 )

No nie - użyłeś call_user_func()/
A co w tym złego ?
Crozin
21.12.2008, 11:58:47
<?php
class Collection{
public function setLoadCallback(){
throw new Exception('...');
}
$method = $args[0];
$obj = $args[1];
call_user_func_array
(array($obj, $method), $args); }
}
class SampleClass{
public function sampleMethod($param1, $param2, $param3){
}
}
try{
$sc = new SampleClass();
$c = new Collection();
$c->setLoadCallback('sampleMethod', $sc, 'param1', 23, 'param3');
}catch(Exception $e){
}
?>
zzeus
21.12.2008, 12:30:30
No tak właśnie teraz mam, ale martwi mnie troszkę to że trzeba pamiętać o kolejności parametrów w funkcji i w takiej samej kolejności podać je w tablicy. Ale reszta działa całkiem fajnie

Pozdrawiam
Cytat(Cysiaczek @ 20.12.2008, 17:01:04 )

PhotoCollection to po prostu obiekt kolekcji z podstawowymi metodami add, remove, get. Gallery w tym modelu to taki punkt dostępu do funkcji - żeby ich w ciele akcji nie pisać, tylko wywołać.
<?php
$g=new Gallery();
$g->getFilesCreatedBefore($time);
$g->getPhoto(1) // szuka w kolekcji
$g->findPattern('*.jpg');
?>
itp.
Tylko jak pisałem - nie zawsze trzeba tak dużo abstrakcji robić, bo jest to nieopłacalne, jeśli wykonujemy np tylko podstawowe operacje na plikach czy wpisach w bazie.
Pozdrawiam
Inaczej mówiąc chodzi Ci o zastosowanie wzorca fasady ?
Pozdrawiam
Cysiaczek
21.12.2008, 12:43:56
Tak, o fasadę właśnie. Zwłaszcza, jeśli uczyni ona korzystanie z kodu bardziej ludzkim.
zzeus
21.12.2008, 12:49:29
No w sumie skróciło by to np. kod wyświetlenia zdjęć z 4 do 2 linijek.
Teraz jest np. tak:
<?php
$_objPhotoCollection = new PhotoCollection();
$_arrParam = array($dbConnection, $_intSite); $_objPhotoCollection->setLoadCallback('getAllPhotos', 'photoFactory', $_arrParam);
echo $_objPhotoCollection->toArray(); ?>
a byłoby tak:
<?php
$_objGallery = new Gallery($dbConnection);
$_objGallery->getAllPhotos($_intSite);
?>
Czy dobrze rozumię zasadę działania fasady ?
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.