Nie koniecznie dla innego programisty. Piszac duza aplikacjie (tzn zlozona), w koncu zapomnisz o czyms. Interfejsy ratuja wtedy skore

Klase definiuje sie jako abstrakcyjna w chwili, kiedy nie chcesz aby ktos utworzyl jej obiekt. Taka klase da sie tylko dziedziczyc, co w praktyce oznacza ze klasa abstrakcyjna nie jest kompletne klasa. Dziedziczenie uzupelnia klase i wtedy mozemy stworzyc dzialajacy obiekt. Pokaze na przykladzie:
Mamy w aplikacji klase wyswietlajaca dane (widok w MVC). Czesto piszemy kilka widokow - np. taki wyswietlajacy dane na podstawie szablonow php. Do tego doliczmy, ze mozemy miec widok wyswietlajacy dane jak leci oraz taki, ktory udekoruje je o cala strone (stopka, naglowek, menu itp.).
Wiadomo, ze takie widoki powinny miec metody taki, jak:
<?php
interface IView
{
public function setAttribute($sAttributeName, $mAttributeValue);
public function setAttributesArray($aAttributeArray);
public function getAttribute();
public function removeAttribute($sAttributeName);
public function __get($sAttributeName);
public function __set($sAttributeName, $mAttributeValue);
public function display();
public function fetch();
}
?>
W ten sposob zdefiniowalismy interfejs dla klas widoku. Od tech chwili, kazda implementujaca klasa ten interfejs bedzie musiala je miec.
Ale pomyslmy przez chwile. Czy klasa widoku normalna i dekorujaca nie bedzie miala takich samych metod getAttribute(), removeAttribute(), __set(), __get()? Po co powielac kod - napiszemy klase abstrakcyjna:
<?php
abstract class View implements IView
{
private $_aAttributes;
public function __construct()
{
$this->_aAttributes
= array(); }
public function setAttribute($sAttributeName, $mAttributeValue)
{
$this->_aAttributes[$sAttributeName] = $mAttributeValue;
}
public function setAttributesArray($aAttributeArray)
{
$this->_aAttributes
= array_merge($this->_aAttributes
, $aAttributeArray); }
public function getAttribute()
{
return null;
$aCurrentAttribute = $this->_aAttributes;
foreach($aArgs as $sKey => $sAttributeName)
{
if(isset($aCurrentAttribute[$sAttributeName])) $aCurrentAttribute = $aCurrentAttribute[$sAttributeName];
else
return null;
}
return $aCurrentAttribute;
}
public function removeAttribute($sAttributeName)
{
if(isset($this->_aAttributes
[$sAttributeName])) unset($this->_aAttributes
[$sAttributeName]); }
public function __get($sAttributeName)
{
$aAttributes = explode(_LANGUAGE_SEPARATOR
, $sAttributeName); return call_user_func_array
(array($this, 'getAttribute'), $aAttributes); }
public function __set($sAttributeName, $mAttributeValue)
{
$this->setAttribute($sAttributeName, $mAttributeValue);
}
public function display()
{
}
}
?>
Dlaczego klasa musi byc abstrakcyjna:
1. Pominmy slowo kluczowe abstract. Proba utworzenia obiektu tej klasy zakonczy sie bledem. Klasa przeciez nie definiuje metody fetch(), ktora wymusza interfejs.
2. Nie chcemy przeciez utowrzyc (najczesciej przez pomylke) obiektu widoku, ktory nie dziala. Lepiej rozszerzac klase (dziedziczyc od niej). W ten sposob zbudujemy klasy widokow, ktore dzialaja, a maja mniej kodu (bo przeciez dziedzicza z tej klasy abstrakcyjnej).
A jak wyglada przykladowy widok?
<?php
class BasicHtmlView extends View
{
private $_sTemplate;
public function fetch()
{
if(!isset($this->_sTemplate
)) throw new ViewException('The template has not been specyfied');
$sTemplateFileName = _DIR_APPLICATION_TEMPLATES . $this->_sTemplate . 'Action.php';
throw new ViewException('The template ' . $this->_sTemplate . ' does not exist');
require_once($sTemplateFileName);
return $sFetched;
}
public function setTemplate($sTemplateName)
{
$this->_sTemplate = $sTemplateName;
}
}
?>
Dodam jeszcze, ze nowy widok nie musi juz implementowac interfejsu, poniewaz dziedziczy implementacje z klasy abstrakcyjnej,
Proste i wygodne

Pozdrawiam, Adrian.