Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> OOP & Interfejsy
KirkoR
post
Post #1





Grupa: Zarejestrowani
Postów: 118
Pomógł: 0
Dołączył: 14.02.2004
Skąd: Warszawa

Ostrzeżenie: (10%)
X----


Witam. Czy ktoś może mi przedstawić szerzej idee interfejsów, do czego służą, kiedy i po co ich uzywać? Bo nigdzie nie mogę znaleźć konkretnych informacji.
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi (1 - 12)
mike
post
Post #2





Grupa: Przyjaciele php.pl
Postów: 7 494
Pomógł: 302
Dołączył: 31.03.2004

Ostrzeżenie: (0%)
-----


A naprawdę szukałeś :?:
forum.php.pl -> search -> interfejs
Working with Class Types: Abstract Classes and Interfaces
Go to the top of the page
+Quote Post
krzysztof f.
post
Post #3





Grupa: Zarejestrowani
Postów: 18
Pomógł: 0
Dołączył: 22.11.2005

Ostrzeżenie: (0%)
-----


Drugi link od mike_mech powinien wszystko wyjaśnić.

Na wszelki wypadek ;)

Interfejsy pozwalają pisać lepiej zorganizowany, czytelniejszy kod oraz oddzielać implementację od właśnie interfejsu. Założenia programowania obiektowego mówią o tym, że powinno się pisać kod bardziej ukierunkowany na interfejs, niż samą implementację. Ułatwia to późniejsze ponowne wykorzystywanie kodu i współpracę między projektantami/programistami. Programowanie (w szczególności programowanie komponentowe http://c2.com/cgi/wiki?ComponentOrientedProgramming) to nie tylko pisanie aplikacji dla końcowego użytkownika. Obecnie programiści piszą kod, który jest wykorzystywany/kupowany później przez innych programistów. Aby praca z obcymi komponentami czy bibliotekami była jak najłatwiejsza, czy też w ogóle możliwa, muszą one dostarczać czytelne API http://en.wikipedia.org/wiki/API. Programistę wykorzystującego taki komponent nie interesuję implementacja (czyli w jaki sposób działają poszczególne zadania), a jedynie interfejs (czyli jakie zadania ma możliwość wykonać).

Mówiąc prościej… interfejs w odniesieniu do obiektu to po prostu lista metod jakie obiekt posiada wraz z typami niezbędnych parametrów i informacją o zwracanej wartości. php umożliwia wymuszanie jedynie typów obiektowych jako parametrów funkcji. Gorzej jest z wartościami zwracanymi, ale ma się to zmienić http://www.php.net/~derick/meeting-notes.h...d-return-values. Póki co jedyny sposób to dobra dokumentacja kodu http://phpdoc.org/.
W taki sposób znając interfejs obiektu wiemy jak go używać. Bo zgodnie z ideą interfejsu wszystkie jego metody muszą być publiczne.

Jak sprawa ma się w praktyce?

Załóżmy, że mamy napisaną aplikację opartą o Front Controller http://www.phppatterns.com/docs/design/the...troller_and_php, który stanowi punkt wejścia do naszej aplikacji. Możemy w nim rejestrować filtry http://java.sun.com/blueprints/corej2eepat...tingFilter.html, które będą wykonywały jakieś operacje na danych wejściowych i wyjściowych. Idea polega na tym, że wykorzystując nasz kontroler w różnych przypadkach, możemy dowolnie komponować zestawy filtrów, lub też tworzyć nowe w miarę potrzeb. W tym celu tworzymy interfejs filtru, z którym będzie współpracował obiekt kontrolera.

  1. <?php
  2. interface IInterceptingFilter
  3. {
  4.  /**
  5. * Operacje wykonywane przed wywołaniem kontrolera
  6. *
  7. * @param Request Obiekt żądania
  8. * @return Request
  9. * @access public
  10. **/
  11.  public function preProcess( Request $oRequest );
  12.  
  13.  /**
  14. * Operacje wykonywane po obsłudze żądania
  15. *
  16. * @param Response Obiekt odpowiedzi
  17. * @return Response
  18. * @access public
  19. **/
  20.  public function postProcess( Response $oResponse );
  21. }
  22. ?>


Stwórzmy teraz przykładowy filtr:

  1. <?php
  2. class TimeExecutionFilter implements InterceptingFilter
  3. {
  4.  
  5.  /**#@+
  6. * @var string 
  7. * @access private 
  8. */
  9.  /**
  10. * Data rozpoczęcia skryptu (format microtime) 
  11. */
  12.  private $_sStart;
  13.  /**
  14. * Data zakończenia wykonywania skryptu (format microtime) 
  15. */
  16.  private $_sEnd;
  17.  /**#@-*/
  18.  
  19.  
  20.  public function preProcess( Request $oRequest )
  21.  {
  22. $this->_sStart = microtime();
  23. return $oRequest;
  24.  }
  25.  
  26.  public function postProcess( Response $oResponse )
  27.  {
  28. $this->_sEnd = microtime();
  29. return $oResponse->set( 'time', $this->_calculateTime( $this->_sStart, $this->_sEnd ) );
  30.  }
  31.  
  32.  /**
  33. * Przeliczenie czasu wykonania strony
  34. * @param string Czas rozpoczęcia (format microtime)
  35. * @param string Czas zakończenia (format microtime)
  36. * @return double Czas wykonania w sekundach
  37. * @access private
  38. **/
  39.  private function _calculateTime( $sStart, $sEnd )
  40.  {
  41. $aEnd = explode( ' ', $sEnd );
  42. $aStart = explode( ' ', $sStart );
  43.  
  44. $dEnd = (float) $aEnd[1] + (float) $aEnd[0];
  45. $dStart = (float) $aStart[1] + (float) $aStart[0];
  46.  
  47. return number_format( $dEnd - $dStart, 4);
  48.  }
  49. }
  50.  
  51. ?>


Z czasem rozwoju aplikacji może się okazać, że przydałby nam się jeszcze inne filtry. Nie ma problemu wystarczy, że zaimplementujemy na nowo nasz interfejs lub zlecimy to komuś innemu. Tak długo jak będziemy trzymać się interfejsu kontroler będzie potrafił sobie z nim poradzić, a my będzimy mogli go spokojnie używać. Chociażby w taki sposób:

  1. <?php
  2.  $oController = new FrontController();
  3.  $oController->addFilter( new AuthenticationFilter( 'login.php' ) );
  4.  $oController->addFilter( new OutputBufferFilter() );
  5.  $oController->addFilter( new TimeExecutionFilter() );
  6.  $oController->run();
  7.  
  8. ?>
Go to the top of the page
+Quote Post
bela
post
Post #4


Administrator PHPedia.pl


Grupa: Developerzy
Postów: 1 102
Pomógł: 2
Dołączył: 14.09.2003

Ostrzeżenie: (0%)
-----


Ja filtry inaczej rozwiązałem. Nie mam 2 metod pre i post, tylko jedną: executeFilter. A niej jest $this->executeNext() co uruchamia następny filterek jaki jest w łańcuszku aż do ExecFiltra który to odpala akcje. Oczywiście jeśli będzię kod przed executeNext, zostanie to potraktowe jako pre filter, a po metodzie execNext jako post filter.


--------------------
Go to the top of the page
+Quote Post
krzysztof f.
post
Post #5





Grupa: Zarejestrowani
Postów: 18
Pomógł: 0
Dołączył: 22.11.2005

Ostrzeżenie: (0%)
-----


I o to chodzi. Cała idea wzorców poleg przecież na tym, że podają one sposób rozwiązania jakiegoś złożonego problemu, a implementację zostawiają programiście pozwalając na dużą swobodę. Moja implementacja filtrów z koleji wygląda mniej więcej tak:

Go to the top of the page
+Quote Post
Ociu
post
Post #6





Grupa: Moderatorzy
Postów: 1 566
Pomógł: 37
Dołączył: 14.05.2003
Skąd: Kraków




Czyli jesli dobrze zrozumiałem, to narzucenie podanych method w interfejsie ?

Swoją drogą, filtry zrobił bym tak:

Klasa Filter, która 'przechowuje' dany filter, potem wrzucamy do ExecuteFilter w którym jest tylko metoda np. process, która uruchamia Filter jako plugin.
Go to the top of the page
+Quote Post
hwao
post
Post #7


Developer


Grupa: Moderatorzy
Postów: 2 844
Pomógł: 20
Dołączył: 25.11.2003
Skąd: Olkusz




Ja może krótko..

Klasy stosujemy jezeli jest zaleznosc "jest jakims\jakas", w przeciwnym wypadku nie zachodzi potrzeba dziedziczenia i stosuje sie szybsze interfejsy.
Go to the top of the page
+Quote Post
bela
post
Post #8


Administrator PHPedia.pl


Grupa: Developerzy
Postów: 1 102
Pomógł: 2
Dołączył: 14.09.2003

Ostrzeżenie: (0%)
-----


Cytat(Ociu @ 2005-12-02 14:22:58)
Czyli jesli dobrze zrozumiałem, to narzucenie podanych method w interfejsie ?

Oczywiście, przecież interfejs ma za zadanie wymusić konkretne metody publiczne w implementującej klasie, w szczególnych wypadkach nie ma wcale metod np. interfejs Serializable, który pozwala na serializowanie obiekt, to bardziej z Javy chociaż ostatnio chyba też w SPL widziałem.

Cytat
Klasy stosujemy jezeli jest zaleznosc "jest jakims\jakas", w przeciwnym wypadku nie zachodzi potrzeba dziedziczenia i stosuje sie szybsze interfejsy.

Hmm, trochę nie kumam ;]
Ja stosuję dziedziczenie tam gdzie chce użyć metod klas rodziców. Czy ja wiem czy interfejsy są szybsze, po prostu nie mają ciała metod. Zresztą tylko interfejsy przydają się głównie przypisaniu aplikacji i pozwalają wykryć za wczasu, że nie ma konkretnej metody, bo polimorfizm w php praktycznie nie istnieje.


--------------------
Go to the top of the page
+Quote Post
hwao
post
Post #9


Developer


Grupa: Moderatorzy
Postów: 2 844
Pomógł: 20
Dołączył: 25.11.2003
Skąd: Olkusz




Bela - nigdy do konca nie wnikałem jak to jest w php smile.gif gdyz nie interesuja mnie to smile.gif

W C# naprzykład interfejsy sa szybsze niz dziedziczenie, pozatym badz co badz zajmuja mniej pamieci.

Jezeli potrzebujesz uzywac metod, to znaczy ze ta relacja zachodzi, ale wprowadzanie jej na hama jest poprostu dlamnie absurdem smile.gif

outputBufforPlugin jest Pluginem smile.gif wiec dziedziczenie powinno zajsc (chyba ze nasza klasa Plugin jest "czysta" i nie ma jakiegos api wykozystywanego gdzies tam)
Go to the top of the page
+Quote Post
Ociu
post
Post #10





Grupa: Moderatorzy
Postów: 1 566
Pomógł: 37
Dołączył: 14.05.2003
Skąd: Kraków




krzysztof f.: jeśli dobrze zrozumiałem, to twoje filtry działają tak, że każdy filter powinien mieć dwa pliki.
1. Jeden plik, który zawiera 'suchy' kod, który jest jakby mózgiem filtru.
2. Drugi plik, który będzie wykonywał całą robotę.
Cały filter leci do FilterChain, który jest zarządzany przez FilterManager, który kieruje filtry do iteratora z ArrayAccess i jesli potrzeba to wyświetla wynik. uf..
rolleyes.gif
Go to the top of the page
+Quote Post
dr_bonzo
post
Post #11





Grupa: Przyjaciele php.pl
Postów: 5 724
Pomógł: 259
Dołączył: 13.04.2004
Skąd: N/A

Ostrzeżenie: (0%)
-----


Cytat
outputBufforPlugin jest Pluginem smile.gif wiec dziedziczenie powinno zajsc

Zgadza sie, masz bazowa klase plugin z abstrakcyjnymi metodami execute() (czy jakos tam) i je przeladowujesz.

Z JAVY (Java 2 Podstawy) cytat ze skrotami (nie chce mi sie tyle przepisywac) [moje dopiski]:
"W javie interfejs nie jest klasa ale zbiorem wymagan dotyczacych klas, ktore chca dostosowac sie do interfejsu

Zazwyczaj dostawca pewnych uslug stwierdza: Jesli twoja klasa jest dopasowana do danego interfejsu, to wykonam usluge. (...) Metoda sort klasy Arrays obiecuje posortowac obiekty tablicy, ale pod jednym warunkiem: obiekty musza nalezec do klas implementujacych interfejs Comparable [nie musza byc tej samej klasy!!!] [musza zaimplementowac jedyna metode: int compateTo( Object innyObiekt );]"

Metoda Arrays.sort() pobiera obiekt "typu" Comparable[] (interfejsy zastapily (w pewnym stopniu) wielokrotne dziedziczenie) -- czyli tablice obiektow implementujacyhc interfejs Comparable i jes sortuje.

Interfejs (np. Telewizora -- przysicki: ON/OFF, Vol+, Vol-, P+, P- ) okresla metody jakie musi zaimplementowac obiekt aby inny obiekt/user (user TV) znajacy obsluge tego interfejsu mogl sie nim poslugiwac (umiesz obsluzyc jeden telewizor, obsluzysz tez setke innych bez czytania manuala). Oczywiscie obiekt moze implementowac inne interfejsy (TV+Mikrofalowka, co co? tongue.gif), co nie przeszkadza userowi znajacy tylko jeden z nich uzuwac tego obiektu.

Inny przydlad: interfejs Zepsuwalne (ale glopie slowo) (jedyna medoda: void zepsuj()), jestes typem czlowieka ktory lubi wszystko psuc (taka abstrakcja, jakby co:)). Obiekty implementujace ten interfejs: TV, Video, Komp, MAC, PC, Sun, Impreze, Atmosfera. Dzieki temu ze implementuja ten interfejs mozesz uzyc na nich metody zepsuj(), nawet jak nie posiadaja wspolnej klasy bazowej.

ufff... DA-END


--------------------
Nie lubię jednorożców.
Go to the top of the page
+Quote Post
krzysztof f.
post
Post #12





Grupa: Zarejestrowani
Postów: 18
Pomógł: 0
Dołączył: 22.11.2005

Ostrzeżenie: (0%)
-----


hmmm

Rozważania na temat w jakich sytuacjach stosować interfejsy a kiedy tworzyć klasy abstrakcyjne są jak najbardziej na miejscu. Nie ma to jednak nic wspólnego z prędkością czy wydajnością.

Cytat
W C# naprzykład interfejsy sa szybsze niz dziedziczenie, pozatym badz co badz zajmuja mniej pamieci.


hwao czy mógłbyś przedstawić jakieś testy wydajnościowe, które ktoś wykonywał i które potwierdzają Twoją teorię? Błędem jest stawianie interfejsów na równi z dziedziczeniem. Obydwa pojęcia oznaczają coś innego i nie są wymienne.

Kiedy potrzebujemy z jakiegoś powodu określić jedynie zestaw metod publicznych dla pisanych w przyszłości klas, nie zajmując się implementacją stosujemy interfejsy. Natomiast gdy na tym etapie pojawia się jakaś wspólna logika dla rodziny klas, którą warto jest zawrzeć w klasie bazowej stosujemy klasy abstrakcyjne. To oczywiście duże uproszczenie, a różnic jest dużo więcej. W php np. nie mamy możliwości dziedziczenia po więcej niż jednej klasie, ale możemy za to implementować więcej niż jeden interfejs, a nawet rozszerzać interfejsy po kilku innych. Ilustruje to przykładowy kod:

  1. <?php
  2. interface IA
  3. {
  4.  public function aa();
  5. }
  6.  
  7. interface IB
  8. {
  9.  public function bb();  
  10. }
  11.  
  12. interface IAB extends IA, IB
  13. {
  14.  public function ab(); 
  15. }
  16.  
  17.  
  18. class AB implements IAB
  19. {
  20. public function aa()
  21. {
  22. echo 'A_B::aa()';  
  23. }
  24.  
  25. public function bb( )
  26. {
  27. echo 'A_B::bb()';  
  28. }
  29.  
  30. public function ab( )
  31. {
  32. echo 'A_B::ab()';
  33. }
  34. }
  35.  
  36. $oAB = new AB();
  37.  
  38. echo $oAB->aa(); // A_B::aa()
  39. echo $oAB->bb(); // A_B::bb()
  40. echo $oAB->ab(); // A_B::ab()
  41.  
  42. ?>


Cytat
bo polimorfizm w php praktycznie nie istnieje.

Jak to?? Już w php4 można było stosować dziedziczenie http://www.php.net/manual/en/keyword.extends.php, które jest przecież głównym narzędziem polimorfizmu.

Cytat
krzysztof f.: jeśli dobrze zrozumiałem, to twoje filtry działają tak, że każdy filter powinien mieć dwa pliki...


Prawie : ) Każdy nowy filtr to dokładnie jedna klasa (i jeden plik) dziedzicząca po abstrakcyjnej klasie InterceptingFilter. Kod klienta operuje jedynie na obiekcie FilterManager, który ukrywa przed nim całą obsługę filtrów. Tworząc instancję menadżera filtrów podajemy w konstruktorze FilterManager::__construct() referencję do docelowego obiektu Target, który wykonuje jakąś operację poprzedzaną i zakańczaną działaniem filtrów. Obiekt Target, podobnie jak filtry, musi implementować interfejs IProcessor. Następnie używając metody FilterManager::addFilter() dodajemy zestaw potrzebnych nam filtrów i w odpowiednim momencie odpalamy przetwarzanie FilterManager::processFilter(). Zgdonie z ideą filtrów, FilterManager::processFilter()wywoła metody InterceptingFilter::preProcess() wszystkich filtrów w kolejności ich dodawania, następnie Target::execute() i metody InterceptingFilter::postProcess() w odwrotnej kolejności.
Go to the top of the page
+Quote Post
hwao
post
Post #13


Developer


Grupa: Moderatorzy
Postów: 2 844
Pomógł: 20
Dołączył: 25.11.2003
Skąd: Olkusz




Cytat(krzysztof f. @ 2005-12-06 12:39:45)
Cytat
W C# naprzykład interfejsy sa szybsze niz dziedziczenie, pozatym badz co badz zajmuja mniej pamieci.


hwao czy mógłbyś przedstawić jakieś testy wydajnościowe, które ktoś wykonywał i które potwierdzają Twoją teorię? Błędem jest stawianie interfejsów na równi z dziedziczeniem. Obydwa pojęcia oznaczają coś innego i nie są wymienne.

Wiem ze oznaczaja co innego, aczkolwiek moga miec "podobne zastosowanie". Co do teori, to jest ona oparta na na ksiezce o c# napisanej przez jednego z tworcow tego jezyka.
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 21.08.2025 - 12:21