příliš abstraktní rozhraní? rubrika: Programování: PHP

5 Milan Lempera
položil/-a 24.4.2013
 
upravil/-a 24.4.2013

Ahoj,

řešíme s kolegy návrh obecných validačních tříd a narazili jsme na následující problém:

Chtěli bychom mít validátory pro různí datové prvky, validátor by byla třída s metodami

  • isValid($value), která by vracela boolean hodnotu
  • validate($value), která by v případě nevalidní hodnoty házela výjimku
  • __invoke($value), která by volala isValid, aby bylo možné poslat validátor jednoduše jako callback

zvažovali jsme rozhraní iValidator, které vynutí uvedené metody. Toto řešení má ale tu nevýhodu, že v konkrétním validátoru není možné vynutit typ validované hodnoty typehintem např. validate(\Datetime $date).

Jako alternativa mě napadá, nedefinovat žádné rozhraní (ani abstraktní třídu), ale na uvedených třech metodách se domluvit jako na konvenci pro validátory.
Někdy by se ale mohlo hodit vynucení validátoru typehintem, takže ještě existuje možnost definovat prázdné rozhraní, a metody opět prohlásit za konvenci, ale to mi taky nepřijde jako ideální řešení.

Díky za vaše odpovědi.

odkaz
4 lukas.starecek
odpověděl/-a 30.4.2013

Nějakou dobu jsme s Milanem o tomto přemýšleli. Můj zatím poslední názor je takový, že bych se nenechal omezovat jazykem. Tedy navrhnout strukturu "dobře" (rozumněj nejlépe, jak nás napadne). K "dobrému" návrhu dle mě také patří (body na základě ostatních reakcí):

  • Rozhraní nelže resp. lže co nejméně, co jde
  • Kód se neopakuje
  • Třída má nějaké zaměření. Na základě tohoto zaměří jdou konfigurační parametry konstruktorem (alternativně setter injekcí) a hodnoty, se kterými třída pracuje, jdou parametry metod

Jako další bych ještě uvedl, že osobně preferuji variantu, kdy je možné samostatně data validovat před tím, než jsou přiřazeny třídě. A to ze dvou důvodů. Jednak nemusím tvořit třídu na to, abych data pouze zvalidoval (dle mě slabý argument) ale hlavně nemusím povolovat třídu s nevalidními daty a před jejich použitím validitu testovat (dle mě silný argument). Při tomto řešení by si totiž člověk nikdy nemohl být jistý, jestli má předaný objekt správná data a prakticky by je musel stále validovat!

Důsledky:

  • V rozhraní musí být metody, které se vyžadují
  • Tyto metody musí mít uvedeny parametry, jaké vyžadují
  • Pro validaci prvku existuje v aplikaci jeden jediný kód na jednom jediném míste - ve validátoru
  • Validovaná hodnota jde jako parametr metod nikoliv do konstruktoru

Jak bylo řečeno p. "Rarouš", na toto by asi byla dobrá generika (nemám vyzkoušeno). Jelikož v PHP nejsou, je potřeba toto obejít. V Javě generika také dříve nebyli a používalo se explicitní typování příp. test instanceof.

Osobně mám rozhraní pro validátory v PHP implementováno takto:

interface iValidator {
 
  public function validate($value);
  public function isValid($value); 
  public function __invoke($value);
 
}

"Typehinting" mám řešen (bohužel) až v runtime

  public function isValid($value) {
    if (!$value instanceof VyzadovanaTrida) {
      throw new \InvalidArgumentException();
//      return false;
    }
 
    // validacni kod
 
  }

Osobně sám se sebou bojuji, jestli po testu instanceof vracet false (tedy validátor říká, že to není platná hodnota - to je úkol validátoru) a nebo vyhazovat vyjímku, protože přišel jiný než očekávaný typ.

Komentáře

  • Anonym : Přesně tohle řešení jsem se snažil doporučit ve svém komentáři, ale asi jsem to nevysvětlil dobře. 30.4.2013

Pro zobrazení všech 7 odpovědí se prosím přihlaste:

Rychlé přihlášení přes sociální sítě:

Nebo se přihlaste jménem a heslem:

Zadejte prosím svou e-mailovou adresu.
Zadejte své heslo.