Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Jak traktowac obiekty?
Forum PHP.pl > Forum > PHP
Beynar
Ostatnio mnie nurtuje pytanie dot. OOP... mianowicie mam nastepujace pytania:

1. Czy wlasciwym jest pisac np. klase user uzywac jej w ten sposob by do kazdej metody podawac jakies argumenty ktore w rzeczywistosci beda odnosic sie do roznych userow? Czy tworzyc instancje klasy danego user i w tym momencie wszystkie metody obiektu nie przyjmuja argumentow dotyczących tego na jakim userze ma wykonywac operacje, poniewaz operuje na obecnym stanie obiektu - danym userze.

2. Jesli przyjac powyzsza idee, to jak rozwiazac problem gdy dany obiekt wyjsciowo ma reprezentowac jakis string. Generowac napis ktory ma zostac wyswietlony. Takich napisow ma byc 30. Tworzyc 30 obiektow tylko po to zeby je wydrukowac? Chyba troche malo optymlanie... z drugiej strony jesli skorzystac z jednego obiektu do budowania tych 30 napisow to moj obiekt zamini sie w mala fabryke i juz nie bedzie tak swietnie implementowal idei obiektowosci (tak mysle, moze blednie).
dr_bonzo
1.
Cytat
1. Czy wlasciwym jest pisac np. klase user uzywac jej w ten sposob by do kazdej metody podawac jakies argumenty ktore w rzeczywistosci beda odnosic sie do roznych userow? Czy tworzyc instancje klasy danego user i w tym momencie wszystkie metody obiektu nie przyjmuja argumentow dot. tego na jakim userze ma wykonywac operacje, poniewaz operuje na obecnym stanie obiektu - danym userze.

Opcja nr 2, to sa wlasnie podstawy obiektowosci: 1 user == 1 obiekt. Bo pierwsza opcja to nic innego niz progr. strukturalne.



2.
Jesli ma reprezentowac string to czemu nie: 1 string == 1 obiekt. A jesli ma GENEROWAC stringi, to powinien ci jeden generator wystarczyc - najlepiej to opisz ten problem bardziej szczegolowo.
Beynar
Dzięki za odpowiedź
Cytat(dr_bonzo @ 19.05.2008, 19:14:17 ) *
2. Jesli ma reprezentowac string to czemu nie: 1 string == 1 obiekt. A jesli ma GENEROWAC stringi, to powinien ci jeden generator wystarczyc - najlepiej to opisz ten problem bardziej szczegolowo.

Opis zagadnienia
Temat już poruszałem na forum ale nie dostałem żadnej odpowiedzi. Chodzi o klase URL która będzie wykorzystywana w dwóch miejscach aplikacji:
1. Router (rutowanie po rzeczywistym http-request, forwardowani, redirect itd...)
2. Widok do budowania linków na stronie

Klasa URL będzie po prostu obsługiwała PATH INFO, co ja nazywam trasą routowania.
Klasa ta będzie posiadała metody do szyforwania linków, oraz uzupełniała (przy budowaniu linków) niektore elementy trasy routowania ktore są nieznajome dla programisty widoku. Tj. sesid, język. Programista w widoku poda tylko url -> build("controller/action/parm0/parm1/parm2") a obiekt url, zaszyfruje oraz doda odpowiednie elementy.

Problematyka
1. Czy programista w widoku powinien tworzyć nowe linki w ten sposób:
  1. <?php
  2. // powolanie obiektu reprezentujacego konkretny url
  3. $url = new url("home/index/34");
  4. // uzyskanie zaszyfrowanego, uzupelnionego, uporzadkowanego linku (string)
  5. $url -> build();
  6. // kazdy kolejny link jest budowany poprzez powolanie nowego obiektu
  7. $url2 = new url("admin/login");
  8. $url2 -> buidl();
  9. ?>

czy tak:
  1. <?php
  2. // utowrzenie obiektu z domyslnymi wartosciami
  3. $url = new()
  4. // korzystanie z tego obiektu jak z fabryki.
  5. $url -> build("home/index/34");
  6. $url -> build("admin/login");
  7. ?>


Skłaniałbym się ku pierwszej metodzie ponieważ wydaje mi się bardziej obiektowa i przejżysta. Jedyną dużą wadą tej opcji jest wydajność. Ilość obiektów = ilość linków, to nie będzie za wolne?
Część własności klasy URL będzie statyczne.

pozdrawiam
dr_bonzo
A ktora chcialo by ci sie pisac 1000 razy w aplikacji?
Ja mam po prostu $h->url_for( 'controller', 'akcja', ....... ); a w srodku dzieje sie magia przetworzenie tych parametrow na stringa i zwrocenie go.
A router jest TYLKO jeden [obiekt], i nie mam obiektow URLi
Beynar
Czyli u Ciebie adres żądania sam router sobie przygotowuje? U mnie to obiekt URL odpowiada za to by dostarczyc routerowi poszczegolne segmenty PATH INFO. ponadto odszyfrowywuje linki (jesli wlaczone szyfrowanie).
Cotter
1. Oba rozwiązania mają wady i zalety i wbrew pozorom user jako reprezentant wszystkich użytkowników nie jest programowaniem strukturalnym. Wielu programistów zadaje sobie pytanie co powinno być modelem. W znanym CakePHP modelem jest cała tabela.

Ja zawsze skłaniałem się ku rozwiązaniu gdzie 1 użytkownik = 1 obiekt User. Głównym jego plusem jest naturalność w korzystaniu i łatwość w operowaniu danymi. Minusem w porównaniu z rozwiązaniem alternatywnym może być szybkość oraz konieczność konwertowania rekordów z bazy danych na obiekty. Jest to szczególnie istotne kiedy na przykład chcesz wyświetlić tabelę podstawowych informacji 100 użytkowników.

Aby radzić sobie z takimi sytuacjami można w klasie User implementować metody statyczne, które upraszczają i przyspieszają wykonywanie kluczowych operacji na wielu użytkownikach na raz. Przykładem takiej metody może być: User::getUsers() która zwraca tabelkę z gotowymi do wyświetlenia informacjami.

Rozwiązanie 1 User = 1 użytkownik + metody statyczne zapewnia jeden punkt dostępowy do całej tabeli użytkowników i posiada zalety obu rozwiązań.

2. Adresy URL warto rozwiązać podobnie jak w przypadku użytkowników. Wszystkie najczęstsze metody warto zaimplementować statycznie, aby nie tworzyć zbędnie obiektów. Nie warto wszystkiego implementować w ten sposób (a tym samym tworzyć jednego obiektu który zawiera wszystkie takie metody), ponieważ skończy się to na implementacji wielu metod wymagających bardzo wielu niezrozumiałych parametrów. Jeżeli występuje potrzeba stworzenia skomplikowanego i nietypowego URLa można stworzyć obiekt i użyć zwykłych metod aby łatwo wygenerować porządany adres.

Osobiście właśnie tak piszę moje strony. Najważniejsze w tego typu pisaniu jest poprawne decydowanie o tym co może być statyczne, a co nie.
zzeus
Właśnie też się ostatnio zastanawiam nad tym problemem. Ale ostatecznie póki co zdecydowałem, że w przypadku kiedy potrzebuję np. listę 100 użytkowników to tworzę sobie metodę w klasie User, która zwraca mi tablicę asocjacyjną z danymi użytkowników. Chociaż wydaje mi się że poprawnie powinno się zwrócić np. tablicę 100 obiektów User. Ale wygodniej mi jest zwrócić tablicę asocjacyjną i później w smarty ją obsłużyć.

Pozdrawiam.
Beynar
Logicznym rozwiazaniem takiej obiektowości userow wydaje mi sie stworzenie oprocz klasy user, klasy users ktora reprezentuje uzytkownikow. Problem w tym aby zachowac zasade:

Obiekt reprezentujacy stan tego czym rzeczywiscie jest

Jak obiekt user moze reprezentowac, czy zwracac naraz 1000 uzytkownikow? Wydaje mi sie ze powyzsza zasada moze prowadzic do calkiem niezlego przenoszenia świata realnego na programistyczny. To by prowadzilo do przejzystosci i jednoznacznosci. Efektem ubocznym moze byc nadlozenie kodu i mniejzsza optymalnosc. Ale po to w koncu jest chyba OOP - zeby nie bylo super-wydajnie tylko przejzsycie. Od super wydajnosci jest strukturalka.


Przykład
Obiekt klasy car oznacza konkretny samochod. Moze zwrocic markę, ilość kół, cene, obecną prędkość jazdy itd... . Ale jakże (obiekt car) może zwrocic naraz marke 1000 samochodow w bazie danych? to nie logiczne. Od zwrocenia 1000 samochodów naraz powinien być w takim razie obiekt cars ktory ze względu na szybkość mógłby operować na tablicach, z kolei ze względu na uniwersalność i przejżystość lepiej żeby zwracał obiekty klasy car - to by było logiczne. Tak jak w rzeczywistości, kiedy mówie o samochodach mam na myśli wiele poszczegolnych obiektów klasy samochód.

Statyczne wspomniane przez @Cotter są być może półśrodkiem - rozwiązaniem. Przyznam, że za ich pomocą mam w tej chwili w swoim frameworku rozwiazaną kwestie budowania linku... ale jakos mnie to nie zadowala... kłóci mi się to jakos z logiką. Wg. mnie statyczna może być np. kierownica we wszystkich samochodach - okrągła. Inne cechy takie same dla danego obiektu (samochodu) można ustatecznić. Takie cechy i metody (jak np. jedź do przodu) ktore sa wspolne dla wszystkich.


jarek_bolo
Cytat(Beynar @ 19.05.2008, 22:46:30 ) *
ciach...
Statyczne wspomniane przez @Cotter są być może półśrodkiem - rozwiązaniem. Przyznam, że za ich pomocą mam w tej chwili w swoim frameworku rozwiazaną kwestie budowania linku... ale jakos mnie to nie zadowala... kłóci mi się to jakos z logiką. Wg. mnie statyczna może być np. kierownica we wszystkich samochodach - okrągła. Inne cechy takie same dla danego obiektu (samochodu) można ustatecznić. Takie cechy i metody (jak np. jedź do przodu) ktore sa wspolne dla wszystkich.


Oj trochę chyba pomieszałeś.
Jeśli chodzi o wspólne cechy to należało by wykorzystać dziedziczenie, a jeśli chodzi o taki sam rodzaj zachowania to użył bym interfejsu.
Czyli abstrakcyjna klasa samochód z wspólnymi cechami i metodami implementująca interfejs definiujący te same zachowania, akcje, które jednak wykonywane są różnie. Bo np. aby jeden samochód ruszył do przodu trzeba włączyć sprzęgło, a następnie jedynkę i spuścić sprzęgło drugi z automatyczną skrzynią biegów wymaga tylko zwolnienia hamulca i naciśnięcia gazu smile.gif Troche chyba zaszalałem teraz z obrazowaniem winksmiley.jpg

Jeśli zaś chodzi o meritum tematu to uważam, że w przypadku małych projektów nie ma co tak bardzo trzymać się obiektówki. Obiektówka daje wymierne korzyści przy dużych projektach, a te z reguły mają środowisko produkcyjne na dedykach, akceleratory, itd. Więc wtedy lepiej mieć dobrze obiektowo zaprojektowany i złożony system, bo ewentualny koszt poprawienia wydajność będzie mniejszy od kosztów rozwijania i konserwowania dużej aplikacji webowej źle napisanej.
Crozin
Cytat
Wg. mnie statyczna może być np. kierownica we wszystkich samochodach - okrągła. Inne cechy takie same dla danego obiektu (samochodu) można ustatecznić. Takie cechy i metody (jak np. jedź do przodu) ktore sa wspolne dla wszystkich.
To co opisałeś to raczej dziedziczenie winksmiley.jpg
Klasa malyFiat i duzyFiat mogą dziedzyczyć po klasie samochod pewne wspólne cechy - np. wspomniana przez Ciebie kierownica. Jest w obu przypadkach okrągła, służy do zmiany położenia kół. Tak więc klasa samochod może zawierać metodę (typu: protected)
  1. <?php
  2. class samochod{
  3. protected method kierownica($srednica = 13){
  4. //coś tam
  5. }
  6. }
  7.  
  8. class malyFiat extends samochod{
  9. //metoda kierownica() jest zaimplementowana
  10. }
  11.  
  12. class duzyFiat extends samochod{
  13. //j/w
  14. }
  15. ?>


Metody statyczne potrzebne są właściwie tylko wtedy, gdy nie mamy obiektu danej klasy i nie chcemy tworzyć jej instnacji, ale chcemy wykonać jakąś metodę tej klasy.

EDIT:
i się spoźniłem
Beynar
Tak macie racje Panowie... troche się zapędziłem z tymi statycznymi smile.gif dziedziczenie jest bardziej do tego przeznaczone. Macie racje.

Nie bede juz tego rozstrząsał, zwróce natomiast uwage ku mojemu realnemu problemowi
Napisałem zarys klasy URL (bez ciał funkcji, jakby interfejs) dość komenatarzy więc nie zrażajcie się długością posta

  1. <?php
  2.  class URL{
  3.  
  4.  /**
  5. * @var array zawiera takie dane jak sesid, jezyk, region itp.
  6. */
  7.  private static $routeHelpers=null;
  8.  
  9.  /**
  10. * @var array kontroler/akcja
  11. */
  12.  private $routeAddress=null;
  13.  
  14.  /**
  15. * @var array parametry
  16. */
  17.  private $routeParms=null;
  18.  
  19.  /**
  20. * wywoluje stringToArray lub arrayToString, jesli wlaczone
  21. * jest szyfrowanie, to przepusci dane przez statyczna metode
  22. * decrypt i ustawi wlasciwosci routeHelpers, routeAddress oraz 
  23. * routeParms
  24. *
  25. * @param string $routeInfo
  26. */
  27.  public function __construct($routeInfo){}
  28.  
  29.  /**
  30. * Metoda dostepowa zwraca wlasciwosc routeHelpers
  31. */
  32.  public function getHelpers(){}
  33.  
  34.  /**
  35. * Metoda dostepowa zwraca wlasciwosc routeAddress
  36. */
  37.  public function getAddress(){}
  38.  
  39.  /**
  40. * Metoda dostepowa zwraca wlasciwosc routeParms
  41. */
  42.  public function getParms(){}
  43.  
  44.  /**
  45. * Jesli wlaczone szyfrowanie to najpierw wywoluje stringToArray
  46. * nastepnie encrypt. Odpowiednio dopelnia link elementami globanymi
  47. * (routeHelpers) na koncu wywoluje arrayToString, dopelnia routeInfo
  48. * do kompletnego URI i je zwraca 
  49. *
  50. * @param string $routePath
  51. */
  52.  public static function build($routePath){}
  53.  
  54.  /**
  55. * odszyfrowuje wartosci tablicy
  56. * @param array $array
  57. */
  58.  private static function decrypt($array){}
  59.  
  60.  /**
  61. * szyfruje wartosci tablicy
  62. * @param array $array
  63. */
  64.  private static function encrypt($array){}
  65.  
  66.  /**
  67. * Rozbija string w tablice po odpowiednim separatorze
  68. *
  69. * @param string $string
  70. */
  71.  private static function stringToArray($string=false){}
  72.  
  73.  /**
  74. * Sklada tablice do stringu po danym separatorze
  75. *
  76. * @param array $array
  77. */
  78.  private static function arrayToString($array=false){}
  79.  }
  80.  
  81.  //-----------------------------------------------------------------
  82.  
  83.  // Zastosowanie w routerze
  84.  $URL = new URL($_SERVER["PATH_INFO"]);
  85.  // gotowa trasa routowania, wystarczy podac do routera
  86.  $URL -> getAddress();
  87.  
  88.  // Zastosowanie w widoku
  89.  URL::build("home/index/87");
  90.  // gotowy link
  91.  ?>


Co mnie boli?
a.. to, że teraz ma prawie same statyczne metody w tej klasie i obiekt traci taką ścisłą obiektowość. A musi tak być, jeśli chce korzystać w statyczny sposób do budowania linków na stronie (z kolei build korzysta z innych statycznych...).

Czekam na wasze pomysły

pozdrawiam, Kuba

Macie moze jakies sugestie do powyzszego kodu.

pozdrawiam
Crozin
To dodaj trochę
  1. <?php
  2. private function trelemorele($args){
  3. //a ja nie robie nic....
  4. }
  5. ?>
Żeby poprawił się stosunek "normalnych" do statycznych biggrin.gif

A tak na serio. To że połowa metod klasy jest statyczna, nie oznacza, że jest to źle napisana klasa. A jeżeli już tak bardzo chcesz mieć wszystko "normalnie" możesz posł€żyć się czymś takim:
  1. <?php
  2. public static function build($routePath){
  3. $obj = new self;
  4. $obj->buildRoutePath($routePath); //ta metoda jest "dynamiczna" i może korzystać z innych "dynamicznych"
  5. }
  6. ?>
Wtedy musisz tylko musisz zawartość konstruktora wrzucić w inną metodę, albo dodać mu jakiś warunek sprawdzający skąd został utworzony obiekt.
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.