Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Leniwa konkretyzacja
Forum PHP.pl > Forum > PHP > Object-oriented programming
athabus
Witam, mam problem z leniwą konkretyzacją (czyli opóźnioną inicjacją niektórych cech obiektów).

Sprawa wygląda tak, że mam kolekcję obiektów -> dajmy na to książek. Kolekcja na początku inicjuje książki -> ale tylko autorów i tytuł ->spis rozdziałów chciałbym aby był inicjowany z "opóźnieniem" - tylko wtedy, kiedy będzie potrzebny.

Generalnie wszystko jest proste jeśli rozważamy to z perspektywy jednej książki -> wystarczy stworzyć obiekt, i przy próbie wywołania metody ksiazka->podajRozdzialy - odczytujemy je z bazy i inicjujemy liste rozdzialow.

Ja natomiast potrzebuję sposobu, aby w razie próby odczytania spisu treści jednej książki, automatycznie odczytać spisy treści pozostałych książek znajdujących się w kolekcji.

Na początku myślałem, że będzi to proste, ale okazuje się, że utknąłem w tym punkcie. Myślałem o wykorzystaniu wzorca obserwatora -> ale tu pojawia się problem, bo każda ksiażka musiałaby mieć referencję do kolekcji książek - co spowoduje zapętlenie -> książka jest elementem kolekcji i jednocześnie kolekcja jest elementem książki... Przyznam się szczerze, że nie próbowałem zapisać kodu tego rozwiązania, więc nie mam 100% pewności, że to by nie działało, ale chyb nie będzie działac...

Czy jest jakiś wzorzecz/ metoda, którą mógłbym wykorzystać do obejścia tego problemu.

Dodam, że jest to dla mnie bardzo ważne, gdyż przykiład jest uproszczeniem, w moim przypadku, gdyby udało mi się rozwiazać ten problem zaoszczędzę dużo pracy bazie danych.
mike
Takie gotowce to ja moge pisać smile.gif

  1. <?php
  2.  
  3. class BooksCollection
  4. {
  5. private $arrExampleTitles = array( 'Przygody Nospora Puchatka', 'Dzieci z Bulerbyn', 'Przygody Tolka Banana', 'W Pustyni i w Puszczy' );
  6. private $arrCollection = array();
  7.  
  8. public function __construct()
  9. {
  10. $intBooksCount = rand( 1, 10 );
  11.  
  12. for( $i=1; $i <= $intBooksCount; $i++ )
  13. {
  14. shuffle( $this->arrExampleTitles );
  15.  
  16. $objBook = new Book( $this->arrExampleTitles[ 0 ] );
  17. $objBook->assignToCollection( $this );
  18.  
  19. $this->addBook( $objBook );
  20.  
  21. }
  22. }
  23.  
  24. public function getBook( $intBookIndex )
  25. {
  26. if( array_key_exists( $intBookIndex, $this->arrCollection ) )
  27. {
  28. return $this->arrCollection[ $intBookIndex ];
  29. }
  30.  
  31. return null;
  32. }
  33.  
  34. public function getRandomBook()
  35. {
  36. if( count( $this->arrCollection ) > 1 )
  37. {
  38. shuffle( $this->arrCollection );
  39.  
  40. return $this->arrCollection[ 0 ];
  41. }
  42. }
  43.  
  44. public function addBook( $objBook )
  45. {
  46. if( $objBook instanceof Book )
  47. {
  48. $this->arrCollection[] = $objBook;
  49. return true;
  50. }
  51.  
  52. return false;
  53. }
  54.  
  55. public function setChaptersCount()
  56. {
  57. foreach( $this->arrCollection as $objBook )
  58. {
  59. $objBook->setChaptersCount();
  60. }
  61. }
  62. }
  63.  
  64. class Book
  65. {
  66. private $objCollection = null;
  67. private $strTitle  = '';
  68. private $intChaptersCount = null;
  69.  
  70. public function __construct( $strTitle )
  71. {
  72. $this->setTitle( $strTitle );
  73. }
  74.  
  75. public function getTitle()
  76. {
  77. return $this->strTitle;
  78. }
  79.  
  80. public function setTitle( $strTitle )
  81. {
  82. $this->strTitle = $strTitle;
  83. }
  84.  
  85. public function getChaptersCount()
  86. {
  87. if( ( $this->objCollection instanceof BooksCollection ) && $this->intChaptersCount === null )
  88. {
  89. $this->objCollection->setChaptersCount();
  90. }
  91.  
  92. return $this->intChaptersCount;
  93. }
  94.  
  95. public function setChaptersCount()
  96. {
  97. $this->intChaptersCount = rand( 1, 10 );
  98. }
  99.  
  100. public function assignToCollection( $objBooksCollection )
  101. {
  102. if( $objBooksCollection instanceof BooksCollection )
  103. {
  104. $this->objCollection = $objBooksCollection;
  105.  
  106. return true;
  107. }
  108.  
  109. return false;
  110. } 
  111. }
  112.  
  113. ?><pre><?php
  114.  
  115. $objBooksCollection = new BooksCollection();
  116.  
  117. echo print_r( $objBooksCollection );
  118.  
  119. $objBooksCollection->getRandomBook()->getChaptersCount();
  120.  
  121. echo print_r( $objBooksCollection );
  122.  
  123. ?></pre>


Przykład taki jak szukałeś, z tym że zamiast listy rozdziałów jest generowana ich liczba jak tylko dla jakiejś książki wywołana zostanie mutoda getChaptersCount().

Nie pisałem komentarzy bo pisałem to na szybko, jak potrzeba coś wytłumaczyć to wołaj.

Jednym słowem książka powinna wiedzieć w jakiej jest kolekcji smile.gif
athabus
Ale się porobiło - człowiek zadaje pytanie, wychodzi, wraca a tu czeka gotowiec od moda - rozpuszczanie userów:D

A tak już serio to dokładnie o to mi chodziło. Z tego co widzę, to obiekt Book posiada referencję do BookCollection.
Myślałem nawet nad takim rozwiązaniem - ale stwierdziłem, że to się nie może udać... a tu niespodzianka - php nie wpadło w rekurencję.

Mike_mech - powiedz mi tylko jeszcze, czy dobrze wnioskuję, ale to jest możliwe dzięki temu, że obiekty book nie zawierają kolekcji tylko wskaźnik na nią? W takim układzie ten przykład działa tylko na php5 bo php4 chyba przekazuej obiekty przez wartość domyślnie(chociaż nie jestem pewien bo nie pisałem w php4)?
Piszę na php5 ale tak pytam, żeby się czegoś dowiedzieć.

Jeszcze raz dzięki za pomoc - moja baza będzie ci wdzięczna :-)

edit
Cytat
private $arrExampleTitles = array( 'Przygody Nospora Puchatka', 'Dzieci z Bulerbyn', 'Przygody Tolka Banana', 'W Pustyni i w Puszczy' );


biggrin.gif
mike
Cytat(athabus @ 22.08.2006, 22:42 ) *
Ale się porobiło - człowiek zadaje pytanie, wychodzi, wraca a tu czeka gotowiec od moda - rozpuszczanie userów:D
Raz do roku i moderatorzy mówią ludzkim głosem.

Cytat(athabus @ 22.08.2006, 22:42 ) *
A tak już serio to dokładnie o to mi chodziło. Z tego co widzę, to obiekt Book posiada referencję do BookCollection.
Myślę, że relacja bedzie tu właściwszym słowem. Referencja za bardzo sie kojarzy ... tongue.gif

Cytat(athabus @ 22.08.2006, 22:42 ) *
Mike_mech - powiedz mi tylko jeszcze, czy dobrze wnioskuję, ale to jest możliwe dzięki temu, że obiekty book nie zawierają kolekcji tylko wskaźnik na nią?
Dokładnie takie cos jest proste do zrealizowania jeśli założy się że nie tylko kolekcja wie wszystko o kolekcjonowanych obiektach, ale też obiekty wiedzą co się z nimi dzieje i maja odwołanie do obiektu kolekcji, która je zawiera.
Wtedy można zrobić takie obserwowanie, a raczej sytuacje kiedy obiekt mówi kolekcji: "Hej, patrz. Coś się stało. Zareaguj."

Cytat(athabus @ 22.08.2006, 22:42 ) *
W takim układzie ten przykład działa tylko na php5 bo php4 chyba przekazuej obiekty przez wartość domyślnie(chociaż nie jestem pewien bo nie pisałem w php4)?
Powiem szczerze. Olewam PHP4 i nie interesuje mnie czy to zadziała i jak zadziała smile.gif
Już od prawie dwóch lat nie programuję w PHP4.

P.S.
Mój kod ma bug'a.
Praca domowa polega na znalezieniu tongue.gif Nie byłbym soba jesli bym podał rozwiązanie biggrin.gif
Podpowiedź: sprawdź co się stanie jeśli będzie tylko jeden obiekt w kolekcji.
athabus
Cytat(mike_mech @ 22.08.2006, 22:52 ) *
P.S.
Mój kod ma bug'a.
Praca domowa polega na znalezieniu tongue.gif Nie byłbym soba jesli bym podał rozwiązanie biggrin.gif
Podpowiedź: sprawdź co się stanie jeśli będzie tylko jeden obiekt w kolekcji.


No chociaż coś - bo jeszcze by sie userzy rozkaprysili biggrin.gif

Dzięki za pomoc - zabieram się za kodowanie.
bigZbig
@athabus - masz powazniejsze zadanie, a mianowicie przekonstruowanie mechanizmu, ktory przedstawil mike_mech w taki sposob aby do pobrania listy rozdzialow dla wszystkich ksiazek w kolekcji uzyc tylko jednego zapytania do bazy danych a nie tylu zapytan ile jest ksiazek.
mike
Dokładnie.
W tej chwili pobranie jednej ilości rozdziałów powoduje że kolekcja pobiera ilości dla wszystkich. Ale dla wszystkich lecąc po kolei i pobierając pojedynczo.
A jak ~bigZbig powiedział to nie może być pętla i dla każdego getChaptersCount() musi to być coś w stylu getAllChaptersCountAndAssignToBooks() smile.gif
athabus
@bigZbig - właśnie po to to robię smile.gif - mam kolekcję obiektów, która do pełnej inicjacji potrzebuje w sumie kilku zapytań (4-5), ale generalnie w 95% przypadków użycia wystarczy jedno zapytanie - normalne jest więc aby użyć w tych obiektach leniwej konkretyzacji - z drugiej jednak strony głupio było aby każdy obiekt wykonywał osobno inicjację swoich dodatkowych cech -> bo wtedy ilość zapytań = ilość el w kolekcji x 3-4 - czyli dokładnie to o czym mówisz.

No i po to mi właśnie było to, co mike_mech nazwał "świadomością obiektu o przynależności do kolekcji".

Tak jak pisałem w pierwszym poście - chciałem użyć wzorca obserwatora, ale bałem się rekurencji (kolekacja tworzy obiekt->obiekt zawiera kolekcję, więc tworzy nową kolekce itp itd) - nie wziąłem jednak pod uwagę że obiekt może zawierać wskaźnik na kolekcję tiredsmiley.gif - w tym przypadku więc spokojnie można użyć obserwatora.
bigZbig
Tak naprawde to co napisal mike_mech jest realizacja wzorca obserwatora (z mala modyfikacja) tyle, ze niesformalizowana tzn obserwator i obserwowany nie implementuja odpowiednich interfejsow np. z biblioteki SPL tj. SplObserver i SplSubject. Tak czy inaczej idea zaczerpnieta jest ze wzorca obserwatora.




---
Wszystko się wydało smile.gif
~mike_mech
Jarod
@mike_mech: w Twoim kodzie gdzieś jest błąd. Pewnie przez to losowanie. Poodświeżaj sobie stronę kilkanaście raz. W linijce 119.
athabus
mike_mech już o tym pisal - problem jest gdy jest 1 obiekt w kolekcji tylko :-)
Jarod
Cytat(athabus @ 27.08.2006, 12:15 ) *
mike_mech już o tym pisal - problem jest gdy jest 1 obiekt w kolekcji tylko :-)


Dlaczego?
mike
Błąd popełniłem w linii 36 w metodzie getRandomBook().
Zwraca ona obiekt z kolekcji, tylko wtedy jeśli zawiera ona więcej niż jeden element:
  1. <?php
  2. if( count( $this->arrCollection ) > 1 )
  3. ?>

A powinna zwracać wtedy kiedy jest więcej niż zero:
  1. <?php
  2. if( count( $this->arrCollection ) > 0 )
  3. ?>


~J4r0d jak dołączasz do dyskusji to prześledź jej wcześniejszy przebieg.
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.