Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP] Obiekt i konwersja na string
Forum PHP.pl > Forum > PHP > Object-oriented programming
shine
Mam taki kod:

  1. <?php
  2.  
  3. class szablon {
  4.  
  5.  
  6. public $nazwa_gry;
  7. public $nazwa;
  8.  
  9. public function ustaw_nazwe($nazwa) {
  10. $this -> nazwa_gry = $nazwa;
  11. return $this -> nazwa_gry;
  12. }
  13. }
  14.  
  15. $obiekt = new szablon;
  16.  
  17. echo 'Nazwa gry to' . $obiekt -> ustaw_nazwe('Gra - wojownicy');
  18.  
  19. class naglowki {
  20.  
  21. public $ktory;
  22. public $gdzie;
  23. public $wynik;
  24. public $page_content;
  25.  
  26.  
  27. public function ustaw($ktory,$gdzie)
  28. {
  29. $this -> ktory = $ktory;
  30. $this -> gdzie = $gdzie;
  31.  
  32. $this -> page_content = file_get_contents($gdzie);
  33. $this -> wynik = str_replace($this -> ktory, file_get_contents("$this -> gdzie"), $this->page_content);
  34.  
  35. //echo $this -> wynik;
  36. }
  37.  
  38. }
  39.  
  40.  
  41.  
  42. //$page_content = file_get_contents("pages/main.html");
  43.  
  44. $czesc = new naglowki;
  45.  
  46. $czesc -> ustaw("!!HEADER!!", 'design/header.html');
  47.  
  48. /*
  49. $page_content = str_replace("GORA", file_get_contents("design/common_tags.html"),$page_content);
  50.  
  51. $page_content = str_replace("NAGLOWEK", file_get_contents("design/header.html"),$page_content);
  52. $page_content = str_replace("LEWA", file_get_contents("design/left_column.html"),$page_content);
  53. $page_content = str_replace("PRAWA", file_get_contents("design/right_column.html"),$page_content);
  54. $page_content = str_replace("STOPKA", file_get_contents("design/footer.html"),$page_content);
  55.  
  56. $page_content = str_replace("DOL", $nazwa_gry,$page_content);
  57. echo $page_content;
  58. */
  59.  
  60.  
  61.  
  62. ?>


dostaje blad:
Cytat
Catchable fatal error: Object of class naglowki could not be converted to string in C:\xampplite\htdocs\gra\index.php on line 33


Probowalem na rozne sposoby, ale nie mam pojecia dlaczego taki blad sad.gif
-=Peter=-
zamień to:
  1. <?php
  2. $this -> wynik = str_replace($this -> ktory, file_get_contents("$this -> gdzie"), $this->page_content);
  3. ?>


na to:

  1. <?php
  2. $this -> wynik = str_replace($this -> ktory, file_get_contents($this -> gdzie), $this->page_content);
  3. ?>
shine
Dzieki, rzeczywiscie bledu juz nie ma smile.gif ale nie wiem dlaczego to co jest zakomentowane powoduje ze strona ladnie wczytuje szablon zamienia miejsca w ktorych sa te teksty i wrzuca tam swoje strony html, a jak dalem wersje swoja to juz jest tylko biale tlo sad.gif ktos wie gdzie moze byc blad ?
Sedziwoj
@shine
Ogólnie to powiem, że nie wiem co chciałeś osiągnąć, ale to co tu jest to jest jakaś papka. Czy to co tu napisałeś w czymś coś ułatwia? Bo mi się wydaje że nie.
Jak chcesz pisać obiektowo, to umieszczaj cały kod w obiektach, podziel funkcjonalnie, niech one coś robią, a nie są tylko pojemnikiem na dane.
Doradzam poczytać, bo to co tu prezentujesz lepiej nie mówić. Kup dobrą książkę przerób od deski do deski, a potem samemu kombinuj. Bo inaczej nauczysz się czegoś co potem będzie ciężko wyplenić.
shine
Wiem, ze moj kod jest brzydki i niepraktyczny, ale juz go pozmienialem tak, ze robi to co sobie zalozylem, podzielony na funkcjonalne kawalki. Jesli chodzi o czytanie to akurat mi tego nie musisz mowic jestem po solidnym teoretycznym przejsciu przez Inzynierie Oprogramowania i jezyki obiektowe, ksiazki o OOP, teraz zaczynam praktykowac wiec niektore rzeczy pisze troche bez sensu dla samej wprawy, a nie dlatego nie wiem ze najpierw powinienem sobie zrobic specyfikacje wymagan pozniej use case'y i diagramy klas itp, ale wszystko powoli
Sedziwoj
Nie wiem czemu przyjąłeś pozycję obronną, ale jak masz takie zaplecze wiedzowe, to ono Ci nic nie daje w praktyce, skoro produkujesz taki kod. Nie chodzi nawet o próbowanie, masz wiele "błędów" z samym kodem obiektów. Właściwości publiczne, nie używanie get'erów i set'erów, nazewnictwo, metody które tak na prawdę nic nie robią, a jak są inne to bez sensu jest to że ich nie umieszczasz, no i wspomniany brak enkapsulacji dla funkcjonalności.
Więc dlatego mówię abyś poczytał, a jak czytasz, to chyba bez zrozumienia. Do tego powinno raczej się zacząć od samej budowy obiektów, a potem przejść na wyższy poziom, bo jak nie zrozumiesz jak działają, jak nimi możesz się posłużyć.
jarek_bolo
Cytat(Sedziwoj @ 1.04.2008, 08:06:53 ) *
... nie używanie get'erów i set'erów...


Czytałem w jednej książce, chyba w tej: http://helion.pl/ksiazki/wzopro.htm że stosowanie getterów i setterów nie jest oznaką podejścia obiektowego. Nie mam książki przed sobą teraz, ale wieczorem w domu przejrze ją jeszcze raz i dokładniej napiszę co autor miał na myśli smile.gif
Sedziwoj
Cytat(jarek_bolo @ 1.04.2008, 13:41:47 ) *
Czytałem w jednej książce, chyba w tej: http://helion.pl/ksiazki/wzopro.htm że stosowanie getterów i setterów nie jest oznaką podejścia obiektowego. Nie mam książki przed sobą teraz, ale wieczorem w domu przejrze ją jeszcze raz i dokładniej napiszę co autor miał na myśli smile.gif


Brak nie oznacza, ale odnoszenie się do zmiennych obiektu bezpośrednio już jest złym nawykiem. (Coś o tym wiem, bo już widziałem takie kody, jak kolega próbował jedną właściwość ukryć bo "coś muz mieniało" to nie mógł, bo nie dało się (sprawdź gdzie to używane jest w większej aplikacji, życzę powodzenia) i nie mógł dojść co ją zmieniało, więc jak dla mnie operacje na czystych właściwościach to porażka.

Więc chętnie posłucham co autor miał do powiedzenia, tylko oby nie wyszła czysto filozoficzna gadka.
jarek_bolo
Zapodam cały rozdział, bo ciekawy i najlepiej odda o co chodzi z tymi getterami i setterami.

Metody zwracające i ustawiające są złe
Jak już wspomniałem, fundamentalną regułą rządzącą systemami obiektowymi jest ukrywanie
przez obiekty ich szczegółów implementacyjnych. Stosowanie tej zasady umożliwia
modyfikowanie implementacji obiektów bez konieczności wprowadzania zmian
w kodzie, który te obiekty wykorzystuje. Oznacza to, że powinieneś unikać stosowania
funkcji zwracających i ustawiających, które z jednej strony niczego nie ułatwiają, a jednocześnie
zapewniają dostęp do szczegółów implementacyjnych (pól) w systemach obiektowych.
Warto zwrócić uwagę na fakt, iż ani przykład systemu terminali ATM, ani
przykład modelu ruchu ulicznego nie wykorzystywał metod zwracających i ustawiających
pola obiektów.

Nie twierdzę przy tym, że Twoje funkcje nigdy nie powinny zwracać wartości, lub że
funkcji get i set nigdy nie należy stosować. Obiekty czasami po prostu muszą przekazywać
swoje dane, aby cały system mógł funkcjonować prawidłowo. Tak czy inaczej,
funkcje get i set często są wykorzystywane w sposób niewłaściwy, a więc w roli
środków zapewniających dostęp do pól, które w przeciwnym razie byłyby prywatne,
zatem ich używanie może prowadzić do poważnych utrudnień. To, co rozumiem przez
właściwe zastosowania tych metod omówię na końcu tego podrozdziału. Obecność metod
zwracających i ustawiających (nazywanych często akcesorami i mutatorami, choć
zdarza się, że słowo akcesor jest używane w odniesieniu do obu tych metod) zwykle oznacza
brak jasności oraz niewłaściwe podejście do rozwiązywanego problemu. Programiści
często umieszczają te metody w definicjach klas, ponieważ najzwyczajniej w świecie
chcą uniknąć myślenia o sposobie komunikowania się obiektów klas w czasie wykonywania
systemu. Użycie metod zwracających pozwala odwlec moment analizy technik
komunikacji do czasu właściwego kodowania. Takie podejście jest przejawem czystego
lenistwa; z pewnością nie jest to oznaka „programowania dla elastyczności”.

Przeanalizujmy banalny przykład, który dobrze pokazuje, dlaczego należy unikać metod
zwracających. W Twoim programie może występować tysiąc wywołań metody getX(),
z których każde zakłada, że wartość zwracana przez tę metodę należy do określonego typu.
Wartość zwracana przez metodę getX() może być składowana np. w zmiennej lokalnej,
zatem typ tej zmiennej musi odpowiadać typowi zwracanej wartości. Jeśli będziesz
musiał zmienić implementację obiektu w taki sposób, że zmieni się typ zmiennej X,
popadniesz w poważne tarapaty. Jeśli dotychczasowym typem zmiennej X był int,
a nowym typem jest long, po wprowadzeniu odpowiedniej zmiany otrzymasz tysiąc
błędów kompilacji. Jeśli rozwiążesz ten problem w sposób niewłaściwy, a więc zastosujesz
operację rzutowania typu zwracanej wartości na typ int, kod będzie co prawda
kompilowany, ale z pewnością nie będzie działał prawidłowo (zwracana wartość będzie
obcinana). Aby uniknąć negatywnych skutków tej zmiany, będziesz musiał zmodyfikować
kod otaczający każde z tysiąca wywołań metody getX(). Zdecydowanie nie chciałbym
się znaleźć w podobnej sytuacji.

Przyjrzyjmy się teraz klasie Money. Ponieważ klasa ta była początkowo pisana wyłącznie
z myślą o obsłudze dolarów amerykańskich, zdefiniowano w niej metodę getValue(),
która zwraca liczbę zmiennoprzecinkową typu double, oraz setValue(), która ustawia
nową wartość. Pierwszy problem polega na tym, że takie rozwiązanie umożliwia zupełnie
nonsensowne działania na reprezentowanych kwotach pieniężnych, co ilustruje
poniższy fragment kodu:
Kod
         Money a, b, c;
         // …
         a.setValue( b.getValue() * c.getValue() );

Co właściwie oznacza pomnożenie dwóch dolarów przez pięć dolarów?

Drugi problem jest jeszcze poważniejszy: może zaistnieć konieczność wprowadzenia do
aplikacji rozwiązań międzynarodowych, a więc umożliwiających między innymi obsługę
wielu różnych walut. Taka zmiana będzie wymagała dodania pola nazwanego currency,
które będzie miało wewnętrznie przypisywane takie wartości jak US_DOLLAR, YEN, LEU,
ZLOTY czy HRYVNA. Stosunkowo drobna zmiana — wielkie problemy. Co w tej sytuacji
będzie zwracała metoda getValue()? Metoda ta nie może po prostu zwracać wartości typu
double, ponieważ sama wartość niewiele Ci mówi. Musisz przecież wiedzieć, z jaką
walutą masz do czynienia. Nie jest też możliwe normalizowanie zwracanej wartości,
np. do dolarów, ponieważ przeliczniki stosowane na rynku walutowym zmieniają się co
minutę. Warto się też zastanowić, co należałoby zrobić z otrzymaną wartością. Nie można
ich przecież tak po prostu wyświetlić, ponieważ wymagałoby to opatrzenia ich symbolem
odpowiedniej waluty. Możesz oczywiście do istniejącej metody getValue() dołączyć
nową metodę getCurrency(), ale od tej chwili cały kod wykorzystujący tę wartość
będzie musiał dodatkowo pobierać informację o walucie i lokalnie normalizować
uzyskiwane wartości do standardowej waluty. Powielenie tego rozwiązania w tysiącu
miejsc istniejącego kodu źródłowego wymagałoby mnóstwa pracy. Musiałbyś też znaleźć
wszystkie okna swojego systemu, w których wyświetlane są kwoty pieniężne —
logika odpowiednich elementów graficznych musiałaby zostać przebudowana do postaci
obsługującej różne waluty. Ta „prosta” zmiana błyskawicznie staje się źródłem ogromnych
komplikacji.

Oto kolejny przykład: przeanalizuj wszystkie problemy związane z polami System.in,
System.out oraz System.err po wprowadzeniu do Javy klas Reader i Writer. Wszystkie
trzy pola były publiczne, co samo w sobie było przekleństwem tego rozwiązania. Samo
zastosowanie odpowiednich otoczek (np. metody System.getOut(), która zwracała pole
System.out) oczywiście nie rozwiązywało problemu — pola System.out i System.err
musiały być (opartymi na formacie Unicode) obiektami klasy Writer, nie (opartymi
na formatowaniu bajtowym) obiektami klasy PrintStream. To samo dotyczyło pola
System.in i klasy Reader. Zmiana zadeklarowanych typów obiektów zawierających pola
System.out nie jest rozwiązaniem wystarczającym. Obiekty klasy Writer są wykorzystywane
w nieco inny sposób niż strumienie wyjściowe. Oba mechanizmy różnią się
przecież semantyką i udostępniają różne metody. W efekcie musisz więc zmienić (lub
przynajmniej sprawdzić) cały kod otaczający, wykorzystujący pole System.out do wyświetlania
na konsoli danych wyjściowych. Jeśli Twój program np. stosował formatowanie
Unicode dla danych tekstowych wyświetlanych za pośrednictwem pola System.
out, będziesz musiał użyć aż dwóch wywołań metody write() do zapisania na konsoli
pojedynczego znaku. Co więcej, będziesz zmuszony do wprowadzenia do swojego
programu dodatkowego kodu wyciągającego bardziej i mniej znaczące bajty znaków
i wyświetlającego je osobno. Cały ten kod będzie jednak trzeba usunąć w wersji opartej
na klasie Writer.

Opisany problem jest efektem siły przyzwyczajenia. Kiedy programiści proceduralni
zaczynają korzystać z Javy, próbują budować kod, który będzie choć trochę przypominał
ich dotychczasowe dokonania. Języki proceduralne nie oferują możliwości
50 Wzorce projektowe. Analiza kodu sposobem na ich poznanie
wykorzystywania klas, ale zawierają zwykle rozwiązania podobne do struktur języka C
(czyli w praktyce klasy bez metod i z samymi polami publicznymi). Dla takich programistów
naśladowanie struktur języka C jest zupełnie naturalne — próbują budować
definicje klas pozbawionych metod i udostępniających wyłącznie publiczne pola.
Kiedy taki programista proceduralny usłyszy gdzieś, że należy stosować pola prywatne,
odpowiednio zmienia ich deklaracje i tworzy publiczne metody get i set. Takie rozwiązanie
nie jest jednak niczym więcej niż niepotrzebnym komplikowaniem publicznego
dostępu do danych. Programiści stosujący tego typu działania z pewnością nie tworzą
systemów obiektowych.

Programiści proceduralni będą argumentowali, że publiczne akcesory otaczające pola
prywatne są o tyle „lepsze” od dostępnych bezpośrednio pól publicznych, że dają znacznie
większą kontrolę nad operacjami modyfikowania wartości pól. Programista obiektowy
stwierdzi natomiast, że każdy dostęp — kontrolowany czy nie — jest źródłem
potencjalnych problemów konserwacyjnych. Dostęp kontrolowany może być co prawda
lepszy od dostępu swobodnego, ale nie zmienia to faktu, że takie rozwiązanie jest z wielu
względów niewłaściwe. Argument o wyższości akcesorów nad bezpośrednim dostępem
w ogóle nie uwzględnia najważniejszej słabości obu rozwiązań — zdecydowana większość
klas i tak nie potrzebuje metod akcesorów (ani mutatorów). Oznacza to, że dobrze
zaprojektowany system przesyłania komunikatów (o sposobach jego projektowania za
chwilę) w większości przypadków pozwala całkowicie wyeliminować metody get i set
oraz w konsekwencji tworzyć klasy, których konserwacja będzie dużo łatwiejsza.



Cd. w następnym poście.

Nie twierdzę, że zwracanie wartości jest złe, lub że powinieneś wyeliminować ze swojego
programu wszystkie metody get — to po prostu niemożliwe. Minimalizowanie udziału
tego typu funkcji w definicjach klas spowoduje jednak znaczne ułatwienia w konserwacji
kodu.

Z czysto praktycznej perspektywy, częste stosowanie metod get i set sprawia, że kod
jest nie tylko bardziej skomplikowany, ale także mniej elastyczny. Przeanalizuj typową
„wszechmogącą” klasę proceduralną, która z innych obiektów zbiera informacje niezbędne
do wykonania jakiegoś zadania. Implementacja tej klasy pełna jest wywołań
zewnętrznych metod get. Co jednak powinieneś zrobić, kiedy okaże się, że odpowiednie
zadania są już wykonywane przez jeden z obiektów udostępniających swoje dane tą
drogą? Czy można przenieść kod wykonujący właściwe zadania z jednej, „wszechmogącej”
klasy w miejsca, w których składowane są niezbędne dane? Wywołania akcesorów
przestają być potrzebne, a cały kod jest dużo prostszy.

Stosowanie metod get i set powoduje też, że program staje się nieelastyczny (nie można
w jego ramach łatwo implementować nowych wymagań biznesowych) i wyjątkowo
trudny w konserwacji. Prawdopodobnie najważniejszą zasadą systemów obiektowych
jest abstrakcja danych, a więc ścisłe ukrywanie implementacji mechanizmów obsługi
komunikatów przed innymi obiektami. To tylko jeden z powodów, dla których wszystkie
Twoje zmienne klasowe (pola klasy niebędące stałymi) powinny być prywatne (deklarowane
ze słowem kluczowym private). Jeśli stworzysz publiczną zmienną klasową, nie
będziesz mógł zmieniać tego pola wraz z ewolucją całej klasy, ponieważ w ten sposób
uniemożliwiłbyś prawidłowe funkcjonowanie kodu zewnętrznego, który z tego pola
korzysta. Z pewnością nie masz ochoty na przeszukiwanie tysiąca zastosowań jakiejś
klasy tylko dlatego, że wprowadziłeś drobną zmianę w jej definicji.

Bezmyślne stosowanie metod zwracających i ustawiających jest niebezpieczne z tych
samych względów, które decydują o zagrożeniach związanych z używaniem pól publicznych
— także metody get i set zapewniają zewnętrzny dostęp do szczegółów implementacyjnych.
Co będzie, jeśli zostaniesz zmuszony do zmiany typu udostępnianego
w ten sposób pola? Przecież będziesz wówczas musiał zmienić także typ zwracany przez
metodę akcesora. Jeśli wartość ta jest używana w wielu miejscach, będziesz musiał
zmienić odpowiednie fragmenty w całym kodzie. Ja wolałbym jednak ograniczyć zakres
koniecznych zmian do definicji pojedynczej klasy. Nie chcę, by prosta modyfikacja przenosiła
się na cały program.

Na podstawie reguły ukrywania szczegółów implementacji można stworzyć wiarygodny
test systemów obiektowych. Czy możesz dokonywać istotnych zmian w definicji pojedynczej
klasy (włącznie z wyrzuceniem całych fragmentów kodu i wstawieniem w ich
miejsce zupełnie nowej implementacji) bez konieczności modyfikowania kodu wykorzystującego
obiekty tej klasy? Tak głęboka modularyzacja oprogramowania bardzo
ułatwia konserwację oprogramowania i pełni zasadniczą funkcję w ocenie jego obiektowości.
Nieprzestrzeganie zasady ukrywania szczegółów implementacji bardzo ogranicza
możliwość stosowania pozostałych mechanizmów obiektowych.

Ponieważ metody akcesorów naruszają regułę hermetyzacji, można bez trudu wykazać,
że systemy, w których często lub niewłaściwie stosuje się tego typu rozwiązania po
prostu nie są systemami obiektowymi. Co więcej, jeśli skrupulatnie przeprowadzisz
proces projektowania (w przeciwieństwie do kodowania ad hoc), szybko stwierdzisz,
że Twój program nie musi zawierać niemal żadnych metod akcesorów. Proces ten jest
więc bardzo ważny.

Zapewne zauważyłeś, że w przedstawionym przykładzie modelowania ruchu ulicznego
w ogóle nie stosowano metod zwracających i ustawiających. Obiekty klasy Car nie udostępniają
metody getSpeed(), także obiekty klasy Road nie definiują metody getAverageSpeed().
Nie potrzebujemy metod getLocation() czy setLocation() w obiektach
klasy Car, ponieważ składujemy informacje o lokalizacji pojazdów w obiektach klasy
Road reprezentujących odcinki dróg, na których te pojazdy aktualnie przebywają. Nie
potrzebujemy też metody setAverageSpeed() w obiektach klasy Road, ponieważ obiekty
te same obliczają średnią prędkość pojazdów. Brak metod zwracających i ustawiających
nie oznacza, że jakieś potrzebne dane nie mogą być przekazywane pomiędzy poszczególnymi
modułami tego systemu — przykładowo, obiekt Road przekazuje informacje
o lokalizacji do obiektów klasy Car. Tak czy inaczej, podczas projektowania systemów
obiektowych należy możliwie głęboko minimalizować przepływy danych. Doskonałym
papierkiem lakmusowym wskazującym na „słuszność” zastosowanych mechanizmów
jest następująca reguła: Nie proś obiektu o informacje, których potrzebujesz
do wykonania jakiejś czynności; zamiast tego proś obiekt zawierający te informacje
o wykonanie tych czynności za Ciebie.

Przykładowo, nie powinieneś stosować przedstawionego wcześniej wyrażenia:
Kod
Money a, b, c;
// …
a.setValue( b.getValue() * c.getValue() );


Zamiast tego zażądaj od obiektu klasy Money wykonania odpowiednich działań za Ciebie:
Kod
Money a, b, c;
// …
a.increaseBy( b );


Nie mówisz już: „daj mi ten atrybut, abym mógł go wyświetlić”. Teraz żądasz czegoś
zupełnie innego: „daj mi możliwą do wyświetlenia wizualizację tego atrybutu” lub
„wyświetl swoją zawartość”.

Kolejnym wyznacznikiem realizacji tej reguły jest szczegółowość operacji. Operacje obszerne
sprowadzają się do jednorazowego żądania od obiektów wykonania dużych zadań.
Szczegółowe operacje żądają od obiektów realizacji stosunkowo niewielkich zadań. Ogólnie,
wolę obszerne metody, ponieważ ich stosowanie upraszcza kod i w wielu przypadkach
eliminuje konieczność stosowania metod zwracających i ustawiających.

Metody akcesorów i mutatorów można eliminować dopiero na etapie budowy modelu
systemu, ponieważ bez dobrze przemyślanego modelu dynamicznego wiarygodne
przewidywanie przyszłych mechanizmów komunikacji obiektów klas jest po prostu
niemożliwe. Oznacza to, że w przypadku braku tego modelu musisz zapewniać jak najwięcej
technik udostępniania danych, ponieważ nie jesteś w stanie przewidzieć, które
z tych technik faktycznie będą konieczne. Taka strategia projektowania przez zgadywanie
jest w najlepszym przypadku nieefektywna, ponieważ w praktyce oznacza stratę
czasu na pisanie niepotrzebnych metod (lub dodawanie zbędnych mechanizmów do implementowanych
klas). Jeśli postępujesz w myśl zasady, że w pierwszej kolejności należy
budować model statyczny, musisz być przygotowany na to, że stracisz mnóstwo
czasu na tworzenie nieprzydatnych lub zbyt elastycznych metod. Co więcej, jeśli niewłaściwy
model statyczny wymusi zbyt duże nakłady na tworzenie niepotrzebnych rozwiązań,
cały projekt może się zakończyć niepowodzeniem; a jeśli mimo to zdecydujesz się
na jego kontynuowanie, koszt konserwacji kodu będzie przewyższał koszt jego ponownego
napisania. Wróćmy teraz do przykładu modelowania ruchu ulicznego, w którym
użyłem modelu statycznego do analizy relacji odkrytych w fazie planowania systemu
przesyłania komunikatów. Nie projektowałem modelu statycznego, by później próbować
na jego podstawie budować model dynamiczny (z uwzględnieniem ograniczeń narzuconych
przez przygotowany wcześniej model statyczny).

Uważne projektując i skupiając się na tym, co chcesz osiągnąć (nie na tym, jak to
zrobić), możesz wyeliminować ze swojego programu znaczną część metod zwracających
i ustawiających.


Treść znajduje się w pierwszym rozdziale książki, a ten jest dostępny jako przykładowy na stronie Heliona smile.gif
Cysiaczek
Myślę, że ma trochę racji. Nie do końca oczywiście, bo zakłada, że każdy kod pisany oop jest aplikacją., To nie prawda, bo spora część to biblioteki, które po prostu muszą posiadać settery i gettery, aby mogły pełnić swoje funkcje. Samo podejście jak poniżej:
Cytat
Zamiast tego zażądaj od obiektu klasy Money wykonania odpowiednich działań za Ciebie:


To po prostu pewien styl pisania. Trzeba przy nim bardzo uważać, aby obiekty nie rozrosły się i nie stały obiektami-śmietnikami. Osobiście preferuję wydzielenie osobnych obiektów do wykonania zadań, które zupełnie nie pasują do żadnego dotychczasowego obiektu. Niestety nie bardzo rozumiem też, dlaczego miałbym zepsuć obiekt odsłaniając jego składowe - autor jest w tym bardzo, ale to bardzo mało przekonywujący. Dziwi mnie twierdzenie, że (konkludując) program uważa się za obiektowy, gdy używa setterów i getterów. To nie prawda, bo musi spełnić szereg innych założeń. Mam też obiekcje co do rozumienia pojęcia hermetyzacja przez niego. On ją rozumie (albo jak tak to odebrałem) na jakimś bardzo wysokim poziomie - nie widzi tego, że obiekt powinien dostarczać interfejs i ukrywać swoje flaki, bo może ktoś zechce zmienić np. nazwę składowej.

Pozdrawiam
Sedziwoj
Z jednej strony autor krytykuje akcesory, a z drugiej sam robi coś czego nie powinno się robić. Co już wspomniał Cysiaczek, za dużo chce ładować w obiekt, jak napisał
Cytat
Teraz żądasz czegoś
zupełnie innego: „daj mi możliwą do wyświetlenia wizualizację tego atrybutu” lub
„wyświetl swoją zawartość”.

Po co obiekt ma się sam wyświetlać? Walamy mnóstwo kodu, obiekt puchnie i rośnie, staje się nieczytelny, bo już nie wiemy co tak na prawdę robi... bo i robi co musi, jak i wyświetla się, zapisuje i bug wie co jeszcze, cokolwiek chce się dodać nowego związanego z obiektem, trzeba to napisać w nim, nie można tego hermetyzować, bo już jest się zależnym od tego co jest w obiekcie, nie od jego interfejsu.

Do tego
Cytat
Ogólnie, wolę obszerne metody, ponieważ ich stosowanie upraszcza kod
Ja nie wiem, ale to wygląda właśnie na pozostałość po proceduralnym sposobie pisania, metody powinny być proste, dlatego nawet powstał Compose Method, aby właśnie kod metod był krótki i treściwy.

Jeszcze jedna rzecz, autor nie mówi aby nie stosować akcesorów, ale aby tego nie robić bezmyślnie, i właściwie zastępować dostęp do właściwości które stały się niewidoczne na zewnątrz. Więc autor bardziej krzyczy, a nie mówi coś ciekawego, bo na początku mówi że to źle money przez akcesory, ale nie podał alternatywnego rozwiązania, a jest nim dla niego aby obiekt money sam się wyświetlał, co jest głupie, do tego coś co wyświetla taki obiekt, niezależnie gdzie się to znajduje musi wiedzieć, że zostały dodana waluta, a jak się dobrze napisze to będzie jedno miejsce. Do tego to jest poważna zmiana w aplikacji, a więc jak się jej nie planowało, to nic dziwnego że będzie trochę roboty przy zmianach, można oczywiście dawać od razu "wszystko, na wszelki wypadek" ale sam autor mówił o przeroście ilości niepotrzebnych elementów, więc jakby sam sobie zaprzeczył.

Ogólnie wizja autora, to obiekty które robią wszystko, z olbrzymią ilością kodu, każda nowa funkcjonalność z nimi związana wymaga zmiany ich samych. Brak podziału funkcjonalnego, na to co dany obiekt robi, tak aby móc opisać to w jednym dwóch zdaniach. Czyli robi się nam tak na prawdę nie obiekt, a moduł jakby i nie ważne że jest obiektem, bo i tak jest do wszystkiego. Wydaje mi się że to mu zostało jako zaszłość po proceduralnym sposobie pisania.
Ale też są pewne elementy z którymi się zgadzam, jak planowanie aplikacji, przed pisaniem, co spowoduje że nie będzie jak to zwykle bywa dodawanie get'era bo muszę coś dostać z obiektu... bo nikt nie planował jak to zrobić, czy da się lepiej.

Czyli podsumowując, autor nie mówi aby nie stosować akcesorów, tylko aby dobrze przemyśleć projekt, bo to zmniejszy ich liczbę. Bo często da się osiągnąć tą samą funkcjonalność w inny lepszy sposób.
jarek_bolo
Czyli konkluzja taka, że w programowaniu obiektowym można coś zrobić sposobem nr1, a kiedyś indziej można zrobić sposobem nr2 bo bardziej pasuje. I żeby było trudniej to oba sposoby mogą być niedobrą praktyką, oba mogą być dobrą praktyką i oba mogą sobie przeczyć smile.gif

Wiwat programowanie obiektowe winksmiley.jpg

Za dużo tutaj dowolności i abstrakcji, przez to jest to takie trudne.
Ale dobry programista powiedział mi kiedyś, że z programowaniem obiektowym to musi Ci coś "zaskoczyć", "kliknąć" w głowie. Zanim to nastąpi to czytasz i czytasz i mało rozumiesz, a po zaskoczeniu objawienie smile.gif

Co do tych getterów i setterów to trzeba pamiętać, że książka z której rozdział zacytowałem jest pod języki kompilowane i z typowaniem zmiennych oraz metod. W PHP nie mamy tego problemu/dobrodziejstwa (zależy jak patrzeć na to), więc i restrykcje co do getterów i setterów z powyższej książki nie są takie restrykcyjne dla PHP.
Sedziwoj
Cytat(jarek_bolo @ 2.04.2008, 17:36:06 ) *
Co do tych getterów i setterów to trzeba pamiętać, że książka z której rozdział zacytowałem jest pod języki kompilowane i z typowaniem zmiennych oraz metod. W PHP nie mamy tego problemu/dobrodziejstwa (zależy jak patrzeć na to), więc i restrykcje co do getterów i setterów z powyższej książki nie są takie restrykcyjne dla PHP.


Tu akurat się mylisz, bo jak zamiast string wyplujesz obiekt, to i tak musisz pozmieniać, bo nawet dynamiczne typowanie nie pomoże.
Ogólnie z te "dobrodziejstwa" raczej sprzyjają złemu programowaniu, gdzie nie wiadomo co się dzieje. A OOP ma za zadanie aby kod był czytelniejszy i łatwiej modyfikowalny (tam między innymi).
jarek_bolo
Ale ja nie napisałem, że w ogóle nie trzeba się przejmować tylko napisałem, że mniej restrykcyjne co znaczy, że wciąż różne reguły obowiązują.
Ale już np. jak inta na stringa (pod warunkiem, że string liczbowy) sobie możesz wachlować wedle potrzeb.

Dobrodziejstwem również tego nie nazywam, bo wolał bym, żeby była ścisła kontrola typów w PHP.
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.