Autor Zpráva
MaK
Profil
Mám dvě třídy A1a A2, které mají obdobné vlastnosti.
To zda bude v celém projektu používat tu či ono třídu řeším pomocí:

if (COSI)
    class A extends A1{};    
else
    class A extends A2{};    

A pak všude používám jen třídu A. Potud všechno funguje. Ale třída A1 vyhazuje vyjímku A1Exception a třída A2 vyhazuje A2Exception.

Pokud to napíšu obdobně:

if (COSI)
    class AException extends A1Exception{};    
else
    class AException extends A2Exception{};    

tak to nejde, neboť AException nezachyti svého předka.

Co teď?

MaK
juriad
Profil
Brzdi, to co prováďíš bys nikdy provádět neměl. Existuje lepší řešení, které nezneužívá dědičnost.
MaK
Profil
juriad:
A jaké je to lepší řešení?
juriad
Profil
Měl bys mít třídu A; a pak třídy A1 a A2, které od A dědí (tedy přesně naopak).
Znát třídu A1 nebo A2 musíš jen v okamžiku, kdy vytváříš instanci (na to můžeš mít statickou metodu). Všude jinde ti stačí vědět, že pracuješ obecně s nějakým potomkem třídy A:

abstract class A {
  public static function create() {
    if (COSI) {
      return new A1();
    } else {
      return new A2();
    }
  }
}

class A1 extends A {}
class A2 extends A {}

Maximum kódu jistě můžeš implementovat obecně (jen jednou) ve třídě A.
MaK
Profil
juriad:
třídu A1 jsem dělal já, třídu A2 někdo jiný. Těžko se shodneme na společném předkovi.
Tori
Profil
MaK:
Těžko se shodneme na společném předkovi
Jak potom můžete ty třídy používat, když třeba mají jiné názvy metod, jiné signatury? To máte ještě na víc místech v kódu tu podmínku if (něco) $instanceA1->něco(); else $instanceA2->něcoJiného($param);?
juriad
Profil
MaK:
Ale obě třídy (A1, A2) musí mít minimálně stejné metody.
Takže stačí do A1 a A2 přidat extends A; a v A definovat abstraktní metody. Časem se prostě v třídách A1 a A2 udělá pořádek.
MaK
Profil
juriad:
Ano maji stejne metody, promenne i konstanty. Alespon ty, ktere pouziva projekt.

Co když cizí třída už nějakého předka má?
Co když je to třída, která je součástí PHP?

Něco jiného by nebylo? Něco jako preprocesor z C:

// A bude nahrazeno A1
#define A A1
juriad
Profil
Nemusí to být dědičnost (zmínil jsem ji z důvodu, že už ji používáš a že je dost pravděpodpbné, že se v A1 a A2 budou opakovat některé metody). Můžeš použít rozhraní (http://php.net/manual/en/language.oop5.interfaces.php); třída může implementovat několik rozhraní. V tom rozhraní budou jen hlavičky funkcí.
Tori
Profil
Pokud jsou A1 i A2 interní třídy PHP a jde vám jen o to, že nevíte, která bude kde dostupná, tak je můžete schovat za adaptér + 2 drivery. Tak budete mít jednu třídu s jediným rozhraním/signaturou + jedinou výjimku. Uvnitř adaptéru bude soukromá proměnná s instancí toho kterého driveru. Vizte např. strukturu dibi.
Joker
Profil
juriad:
Takže stačí do A1 a A2 přidat extends A;
Pokud to je cizí třída, nepřipadá mi to moc vhodné. Můžu taky používat nějaký balíček tříd spravovaný někým jiným a pak je dost nepraktické si v něm dělat svoje úpravy do každé verze na kterou aktualizuji.

MaK
třídu A1 jsem dělal já, třídu A2 někdo jiný. Těžko se shodneme na společném předkovi.
No a proč nemůže A1 být potomkem A2?
To mi připadá jako logická cesta, když mám cizí třídu a chci ji přepsat: Podědím ji a pak si přepíšu to co potřebuji.
MaK
Profil
Tori:
Jestli tomu dobře rozumím, napsal bych adapter, ktery by kopíroval metody,konstanty, PROMENNE!? obou tříd a v každé metodě měl jeden řádek:

return $service->metoda(....);

A ještě drivery? To je něco co obalí současné A1 a A2? Nebo to jsou již A1 a A2.
Tori
Profil
No, vlastně vzoru Adapter spíš odpovídají ty "drivery". Sloužily by k tomu, aby se srovnaly rozdíly mezi A1 a A2, pokud tam nějaké jsou.
Třeba u té DB vrstvy máte drivery pro MySQL / MySQLi / MSSQL / ..., které zakrývají jejich vzájemné odlišnosti a dodržují nějaké společné rozhraní, třeba IDbDriver. Nadřízená třída Db potom používá jen $this->db->query("...") a nemusí se starat o to, jestli se k databázi připojila přes Mysql/Mysqli/jiné rozhraní, protože $this->db má vždycky stejné rozhraní.
Ale možná to není potřeba. Nepochopila jsem úplně, které třídy můžete změnit a které ne.
MaK
Profil
Díval jsem se jak to dělá DIBI. Ano, pokud mám dostatek času, nebo jsem autorem něčeho jako je DIBI, pak mohu puvodní třídy obalit drivery. Nad ti postavit adaptér a na konci dne si řeknu: "To jsem si pěkně zaprogramoval." :)

Díky všem za snahu.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: