Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Problem z zachowaniem hermetyzacji.
Forum PHP.pl > Forum > PHP > Object-oriented programming
daniel1302
Witam mam takie klasy(klasy są pisane dla przykładu z głowy).
  1. <?php
  2. abstract class Punkt
  3. {
  4. private $x;
  5. private $y;
  6. private $type;
  7.  
  8. public function setX($x) {.......}
  9. public function getX() {.......}
  10.  
  11. public function setY($y) {.......}
  12. public function getY() {.......}
  13.  
  14. .
  15. .
  16. .
  17. }
  18. ?>

I to jest klasa główna, wszystkie punkty będą miały te cechy($x,$y, $type)
Będą punkty które posiadają tylko te cechy np:
  1. <?php
  2. class StandardowyPunkt extends Punkt
  3. {
  4. }
  5. ?>

i tutaj nie ma problemu.

Ale będą punkty które będą posiadały dodatkowe cechy np wysokośc, kolor, obrazek, zależnie od użytego grafu(mam różne typy grafów).
  1. <?php
  2. class RozszezonyPunkt extends Punkt
  3. {
  4. private $wysokosc;
  5. private $color;
  6. private $obrazek;
  7.  
  8. public function set*() { .... }
  9. public function get*() { .... }
  10. }
  11. ?>


I podczas użycia odpowiedniego grafu wybieram odpowiedni opis punktu np

  1. <?php
  2. class GrafGalileusza extends Graf
  3. {
  4. public function __construct($file, $classPunkt)
  5. {
  6. //Prasuj plik $file.XML do zmiennej $graf
  7.  
  8. if (!class_exists($classPunkt))
  9. throw new Exception(....);
  10.  
  11. //Sprawdź czy klasa dziedziczy po Punkcie
  12. $Test = new $classPunkt ();
  13. if (($Test instanceof 'Punkt') === false)
  14. throw new Exception(...);
  15.  
  16. foreach($graf as $coords => $v)
  17. {
  18. //$coords jest typu(X:Y)
  19. list($x, $y) = explode(':', $coords);
  20. $this -> graf[$x][$y] => new $classPunkt();
  21. $this -> graf[$x][$y] -> setWysokosc();
  22. $this -> graf[$x][$y] -> setColor();
  23. $this -> graf[$x][$y] -> set*();
  24. ...
  25. }
  26. }
  27. }
  28. ?>

Pytanie mam właśnie do tego momętu:
Gdy ktoś poda jako $classPunkt klasę StandardowyPunkt a klasa GrafGalileusza musi używać klasy RozszezonyPunkt, to wystąpi błąd.
  1. Co zrobić w takiej sytuacji?

Sam się strasznie gmatwam z tym.

Myślałem, żeby zrobić jedną klasę Punkt i do niej dodawać wszystkie cechy punktu które będe używał, lub ktoś sobie doda gdy będzie potrzebował innej cechy.

  1. <?php
  2. final class Punkt
  3. {
  4. private $x;
  5. private $y;
  6. private $type;
  7.  
  8. private $wysokosc;
  9. private $color;
  10. private $obrazek;
  11.  
  12. .
  13. .
  14. .
  15. }
  16. ?>


Tylko czy tutaj użytkownik nie ma za wielkiej swobody?
Co możecie mi polecić?

Chyba, że na stałe ustalać w klasie GrafGalileusza jaka klasa punktu ma być używana i np zrobic PunktGalileusza

  1. <?php
  2. class GrafStandardowy extends Graf
  3. {
  4. private $opisPunktu = 'StandardowyPunkt';
  5. }
  6. ?>


  1. <?php
  2. class GrafGalileusza extends Graf
  3. {
  4. private $opisPunktu = 'RozszeżonyPunkt';
  5. }
  6. ?>


  1. <?php
  2. class GrafOli extends Graf
  3. {
  4. private $opisPunktu = 'PunktOli';
  5. }
  6. ?>


Pytania pogrubiłem.

Proszę o odpowiedź i dziękuje.
mortus
Ciężko jednoznacznie odpowiedzieć na Twoje pytania, bo wszystko zależy od założeń tego projektu. Zauważ tylko, że jeśli GrafGalileusza składa się tylko z punktów rozszerzonych, to ani użytkownik, ani jakaś klasa/metoda pośrednia nie powinny mieć możliwości podania z jakiej klasy punktu korzystamy tworząc ten graf. Przecież to musi być właśnie RozszerzonyPunkt i koniec. W tym przypadku trzeba tylko zweryfikować, czy dane zawarte w pliku xml, służącym do wygenerowania grafu, rzeczywiście odpowiadają klasie RozszerzonyPunkt. Można ewentualnie odpowiednią informację umieścić w tym pliku xml. Wszystko jednak zależy od Twoich potrzeb.

Przykład jest troszkę niedopracowany, więc ciężko tutaj dywagować na jakiekolwiek temat.
Crozin
PHP nie wspiera żadnego mechanizmu w stylu typów generyczych z Javy czy szablonów z C++. Ciężko więc w czasie wykonywania o zarządzanie typami.

1. Jakiś taki dziwny ten graf się wydaje... taki nie grafowaty wink.gif Ani tu wierzchołków tylko punkty, ani tu krawędzi tylko mapa. Zmień nazwę na mapę czy jakiś układ punktów, bo trochę mylące to jest w tej chwili.
2. Konstruktor obiektu mapy (tu: grafu) raczej nie powinien zajmować się pobieraniem danych z pliku i uzupełnianiem siebie. Bo co jak zmienisz sobie źródło albo format danych? Dane wprowadzaj z zewnątrz.
3. Do sprawdzenia czy dana klasa dziedziczy po innej możesz skorzystać z mechanizmu refleksji (Reflection API) albo funkcji is_subclass_of. Tworzenie obiektu tylko po to by sprawdzić czy jego typ jest odpowiedni to zły pomysł - szczególnie dlatego, że trzeba by uwzględnić argumenty konstruktora oraz fakt, że tworzenie tego typu obiektu może być kosztowne.
4. Mapa oraz Punkt powinny być interfejsami.
5. Wiem, że to przykład, ale nigdy nie powinieneś rzucać wyjątkami klasy Exception.

Co do samego problemu. W pełni statycznego typowania po prostu w PHP w tym przypadku nie osiągniesz. Mógłbyś próbować robić jakieś protezy typu __construct(RozszerzonyPunkt $punktBazowy) i później klonować ten obiekt w momencie gdy potrzebna Ci nowa instancja, ale to strasznie kulawe i podatne na błędy rozwiązanie. Przekaż odpowiednią klasę (przez mechanizm refleksji) i w czasie wykonywania sprawdzaj:
  1. public function __construct(ReflectionClass $class) {
  2. if (!$class->implementsInterface('RozszerzonyPunkt')) { // czy tam sprawdzanie dziedziczenia po konkretnej klasie
  3. throw new InvalidArgumentException(sprintf('Argument $class powinien być RozszerzonymPunktem (refleksja), podano: %s', $class->getName()));
  4. }
  5. }
  6.  
  7. // .....
  8.  
  9. $map = new Map(new ReflectionClass('Rozszerzony punkty'));
PHP nie ma możliwości osiągnięcia tutaj statycznego, silnego typowania - język na to nie pozwala.
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.