Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> Inheritance vs. interface dla takich samych metod., Klasy dziedziczące mają te same metody. Powinny dziedziczyć?
trzczy
post
Post #1





Grupa: Zarejestrowani
Postów: 460
Pomógł: 49
Dołączył: 5.06.2011

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


Kiedy klasy dziedziczące mają takie same metody, to lepiej by dziedziczyły te metody od klasy nadrzędnej, czy miały te metody "przykazane" przez interface i umieszczone w sobie? Takie 2 rozwiązania pokazuję poniżej. Które jest bardziej poprawne?
  1. //example 1
  2. interface Person {
  3. function getName();
  4. function setName($name);
  5. function getHobby();
  6. function setHobby($hobby);
  7. }
  8. class Person2 implements Person{
  9. private $name;
  10. private $hobby;
  11. public function getName()
  12. {
  13. return $this->name;
  14. }
  15. public function setName($name)
  16. {
  17. $this->name = $name;
  18. }
  19. public function getHobby()
  20. {
  21. return $this->hobby;
  22. }
  23. public function setHobby($hobby)
  24. {
  25. $this->hobby = $hobby;
  26. }
  27. }
  28. class Person3 implements Person{
  29. private $name;
  30. private $hobby;
  31. public function getName()
  32. {
  33. return $this->name;
  34. }
  35. public function setName($name)
  36. {
  37. $this->name = $name;
  38. }
  39. public function getHobby()
  40. {
  41. return $this->hobby;
  42. }
  43. public function setHobby($hobby)
  44. {
  45. $this->hobby = $hobby;
  46. }
  47. }
  48. //example 1 end
  49.  
  50. //example 2
  51. abstract class Human{
  52. protected $name;
  53. protected $hobby;
  54. public function getName()
  55. {
  56. return $this->name;
  57. }
  58. public function setName($name)
  59. {
  60. $this->name = $name;
  61. }
  62. public function getHobby()
  63. {
  64. return $this->hobby;
  65. }
  66. public function setHobby($hobby)
  67. {
  68. $this->hobby = $hobby;
  69. }
  70. }
  71. class Human1 extends Human{
  72. protected $name;
  73. protected $hobby;
  74. }
  75. class Human2 extends Human{
  76. protected $name;
  77. protected $hobby;
  78. }
  79. //example 2 end
  80.  
  81. //TESTING
  82. $Mark = new Person2();
  83. $Mark->setName('Mark');
  84. echo "{$Mark->getName()}<br>"; //Mark
  85. $Mark = new Human2();
  86. $Mark->setName('Mark');
  87. echo "{$Mark->getName()}<br>"; //Mark
  88.  


Z góry dziękuję
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi
droslaw
post
Post #2





Grupa: Zarejestrowani
Postów: 98
Pomógł: 33
Dołączył: 10.05.2011
Skąd: Krak

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


trzczy, Damansson ma rację, w tutorialu żadne metody nie są dublowane. Wydaje się, że rzeczywiście nie zrozumiałeś jeszcze dobrze programowanie obiektowego.

AbstractFactory jest interfejsem czyli nie posiada implementacji. Zawiera tylko deklarację metod (deklarację nie definicję bo definicja to implementacja metody).
Każda klasa implementująca interfejs AbstractFactory definiuje metody zadeklarowane w tym interfejsie, ale nie jest to duplikacja. Dzięki temu masz dwie różne implementacje tego samego interfejsu. To znaczy możesz używać obiektu dowolnej z klas pochodnych w dokładnie ten sam sposób, chociaż każda klasa będzie zachowywać się trochę inaczej (czyli korzystasz z polimorfizmu).

Zaleta tego jest taka, że kod który używa obiektu dowolnej z klas implementujących ten interfejs nie musi brać pod uwagę, z jaką klasą konkretnie ma do czynienia. Kod przez to będzie prostszy w zrozumieniu, rozbudowie i testowaniu.

Ktoś u góry podawał już przykład z klasą Storage. Powiedzmy że tworzysz aplikację, która zapisuje jakieś wiadomości do plików lub bazy.

Kod nie był testowany i może zawierać błędy.
  1. <?php
  2.  
  3. interface StorageInterface
  4. {
  5. public function save($message);
  6. }
  7.  
  8. class FileStorage implements StorageInterface
  9. {
  10. private $dirPath;
  11.  
  12. public function __construct($dirPath)
  13. {
  14. $this->dirPath = $dirPath; // ustawiasz katalog(folder) w jakim zapisywać pliki
  15. }
  16. public function save($message)
  17. {
  18. // tu masz kod zapisujący do pliku
  19. }
  20. }
  21.  
  22. class DbStorage implements StorageInterface
  23. {
  24. public function __construct($dbName, $userName, $passwd, $host)
  25. {
  26. // tu łączymy się z bazą
  27. $this->conn = connect_some_db($dbName, $userName, $passwd, $host);
  28. }
  29.  
  30. public function save($message)
  31. {
  32. // tu zapisujemy do bazy
  33. }
  34. }
  35.  
  36. abstract class AbstractRequestHandler
  37. {
  38. protected $storage;
  39.  
  40. public function __construct(StorageInterface storage)
  41. {
  42. $this->storage = storage;
  43. }
  44.  
  45. abstract public function handleRequest(Request $request);
  46. }
  47.  
  48. class ARequestHandler extends AbstractRequestHandler
  49. {
  50. public function handleRequest(Request $request)
  51. {
  52. // tu pobieramy dane z requesta, generujemy wiadomość
  53. // i zapisujemy
  54. $this->storage->save($message);
  55. }
  56. }
  57.  
  58. class BRequestHandler extends AbstractRequestHandler
  59. {
  60. public function handleRequest(Request $request)
  61. {
  62. // tu pobieramy dane z requesta
  63. // generujemy wiadomość w zupełnie inny sposób niż w klasie ARequestHandler
  64. // i zapisujemy
  65. $this->storage->save($message);
  66. }
  67. }
  68.  


  1. <?php
  2.  
  3. // ... tu mamy trochę kodu, tworzymy obiekt Request itp.
  4. $storage = FileStorage('messages/');
  5. $requestHandler = ARequestHandler($storage);
  6. $requestHandler->handleRequest($request);
  7.  


Ten przykład pokazuje, jak łatwo można zmieniać sposób zapisu wiadomości w aplikacji. Wystarczy zmienić jedną linijkę (stworzyć obiekt klasy DbStorage zamiast FileStorage), a obiekty RequestHandler będą zapisywać wiadomości do bazy danych zamiast do plików. Chcesz zmienić sposób generowania wiadomości? Znowu zmieniasz jedną linijkę ARequestHandler na BRequestHandler.

Obiekty StorageInterface i AbstractRequestHandler możesz tworzyć np. na podstawie pliku konfiguracyjnego przy stracie aplikacji i dalej nie obchodzi Cie z jakiej implementacji korzystasz. Przez to możesz zmieniać zachowanie aplikacji w pliku konfiguracyjnym.

Klasa zajmująca się zapisem do bazy jest interfejsem, ponieważ jedyną wspólną rzeczą dla wszystkich klas zapisujących wiadomości jest to, że aby zapisać wiadomość trzeba wywołać metodą save z jednym argumentem(php 5.x niestety nie pozwala ograniczyć typu argumentu do stringa w deklaracji metody). AbstractRequestHandler jest klasą abstrakcyjną, ponieważ jej klasy pochodne mają wspólny kod (konstruktor).

Zauważ że sposób zapisu i sposób generowania wiadomości zmieniasz niezależnie, dzięki temu że wydzieliliśmy te dwie odpowiedzialności od siebie. Gorszym rozwiązaniem byłoby definiowanie sposobu generowania wiadomości i zapisu w jednej klasie, wtedy moglibyśmy mieć klasy ARequestHandlerFileStorage, ARequestHandlerDbStorage, BRequestHandlerFileStorage itd.

Zanim zacznie się uczyć wzorców projektowych, warto dowiedzieć się trochę na temat ogólnych zasad programowania obiektowego albo kupić dobrą książkę na temat wzorców. W internecie nigdy nie trafiłem na źródła z dobrym wprowadzeniem do programowanie obiektowego, nigdy też nie widziałem w internecie dobrych przykładów.

Jeszcze co do interfejsów: to pokazuje gdzie mają przewagę nad klasami abstrakcyjnymi przykłady są w javie ale każdy powinien zrozumieć.

Ten post edytował droslaw 13.12.2015, 23:24:01
Go to the top of the page
+Quote Post

Posty w temacie
- trzczy   Inheritance vs. interface dla takich samych metod.   12.12.2015, 13:32:56
- - droslaw   W przykładzie, który podałeś klasy są identyczne d...   12.12.2015, 14:43:14
|- - trzczy   Cytat(droslaw @ 12.12.2015, 14:43:14 ...   12.12.2015, 15:32:26
- - Fred1485   Tak moimi słowami, klasę abstrakcyjną czy interfej...   12.12.2015, 15:41:38
- - Comandeer   Osobiście spotkałem się z podejściem, gdzie interf...   12.12.2015, 19:00:55
- - trzczy   Dzięki za odpowiedzi. Dla mnie wynika z tego, że n...   12.12.2015, 22:37:35
- - Damonsson   To nie jest kwestia żadnego wyboru. Do czego inneg...   13.12.2015, 00:36:28
|- - trzczy   Damonsson, nie rozumiesz pytania. Chodzi o dublowa...   13.12.2015, 01:07:19
- - viking   Ale Damansson dobrze Ci odpowiedział i według mnie...   13.12.2015, 10:42:44
|- - trzczy   Cytat(viking @ 13.12.2015, 10:42:44 )...   13.12.2015, 18:42:16
- - Comandeer   CytatW interface nie ma definicji metod. Są nazwy ...   13.12.2015, 18:53:29
- - Pyton_000   O jakim dublowaniu mówisz. Bo tutaj jedynie dublow...   13.12.2015, 19:08:52
- - droslaw   trzczy, Damansson ma rację, w tutorialu żadne meto...   13.12.2015, 22:18:07
- - trzczy   Cytat(Pyton_000 @ 13.12.2015, 19:08:5...   14.12.2015, 08:28:08
- - Pyton_000   Settery i gettery to nie problem. O ile nie mają s...   14.12.2015, 08:33:13
- - droslaw   Cytat(trzczy @ 14.12.2015, 08:28:08 )...   14.12.2015, 12:16:07
- - Matrix12   W przykładzie gdzie implementujesz interfejs chodz...   15.12.2015, 08:00:27
|- - trzczy   Jeszcze się gubię w tym branżowym słownictwie... ...   17.12.2015, 01:13:47
- - Pyton_000   Możesz nazwać jak chcesz np: StorageInterface Sto...   17.12.2015, 10:06:18
|- - trzczy   Cytat(Pyton_000 @ 17.12.2015, 10:06:1...   17.12.2015, 12:35:52
- - Pyton_000   tak, tylko weź pod uwagę to że samego Interface ni...   17.12.2015, 12:37:16
- - viking   Nie było przypadkiem w którymś PSR że interface ma...   17.12.2015, 12:50:28
- - Pyton_000   Było https://github.com/php-fig/fig-standards/bl...   17.12.2015, 14:01:21


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

 



RSS Aktualny czas: 24.12.2025 - 08:57