IMPORTANT: Per accedir als fitxer de subversion: http://acacha.org/svn (sense password). Poc a poc s'aniran migrant els enllaços. Encara però funciona el subversion de la farga però no se sap fins quan... (usuari: prova i la paraula de pas 123456)

Inheritance

  • Paraula clau: extends
  • Relació: is-a
  • La classe fila és com la classe pare (hereta el codi del pare) però s'especialitza o té funcionalitats que no té el pare

Resources:


Relació is-a:

techniquesfig1-100158308-orig.gif

Composition

  • Paraula clau: implements si no es volen acoblar les classes i es vol permetre en polimorfisme
  • Relació: has-a

techniquesfig2-100158309-orig.gif

Un exemple ens pot ajudar a comparar amb herència (extret de https://www.youtube.com/watch?v=wfMtDGfHWpA):

Robot
 .drive()
    
  CleaningRobot
   .clean()
  
  MurderRobot
   .kill()
 Animal
  .poop() //cagar
 
  Dog
   .bark() //lladrar
 
  Gat
   .meow()

El problema és com podem fer un Robot Gos o un Robot Cagador? Amb composició és millor que herència:

dog = pooper + barker
cat = pooper + meower
CleaningRobot = driver + cleaner
murderRobot = driver + killer
murderRobotDog = driver + killer + barker

És a dir amb la composició creem objecte no tant pel que fan com pel que són. Però com fem la composició? La forma més bàsica de composició és utilitzar una classe dins d'un altre (creant una dependència entre les classes):

class Barker {
    public bark() {
     echo "Guau!";
    }
}
class Dog {
    private barker = new Bark();
    public bark() {
    $this->barker->bark();
    }
}
nota: que dos classes estiguin relacionades implica en certa manera un cert grau de Coupling (Acoblament) però el desacoblament 100% no existeix i en tot cas podem utilitzar tècniques com Dependency Injection i els DIC o  Dependency Injection Container

Millor doncs:

class Dog {
    private barker;
    public __construct(Barker $barker) {
       $this->barker = $barker;
    }
    
    public bark() {
    $this->barker->bark();
    }
}

Però encara millor si són més genèrics i utilitzem polimorfisme utilitzant interficies per podem canviar en temps real (polimorfisme) la dependència.

Vegem com utilitzant interfícies podem desacoblar més les classes

Horizonta code reuse =

Don't do (Don't Use Inheritance for Horizontal Code Reuse):

class Persistable
{ 
  public function persist()
  {
    apc_store(get_class($this) . $this->id, serialize($this));
  }

  public static function restore($id)
  {
    return unserialize(apc_fetch(get_class($this) . $id));
  }
}

class Book extends Persistable
{
  // some methods
}

class Author extends Persistable
{
  // some methods
}

En canvi es pot utilitzar un patró tipus Service Design pattern basat en la composició

class PersistenceService
{ 
  public function persist($object, $class)
  {
    apc_store($class . $object->id, serialize($object));
  }

  public static function restore($id, $class)
  {
    return unserialize(apc_fetch($class . $id));
  }
}

I afegir a les classes Book i Author el servei (NOTA: a l'exemple següent utilitzem una mètode setPersistence millor encara utilitzar Dependency Injection )

class Book
{
  // some methods

  protected $persistence;

  public function setPersistence(PersistenceService $persistence)
  {
    $this->persistence = $persistence;
  }

  public function persist()
  {
    $this->persistence->persist($this, get_class($this));
  }

  public static function restore($id)
  {
    return $this->persistence::restore($id, get_class($this));
  }
}

class Author
{
  // some methods

  protected $persistence;

  public function setPersistence(PersistenceService $persistence)
  {
    $this->persistence = $persistence;
  }

  public function persist()
  {
    $this->persistence->persist($this, get_class($this));
  }

  public static function restore($id)
  {
    return $this->persistence::restore($id, get_class($this));
  }
}

Encara millor si podem utilitzar un Mixin/Trait:

trait Persistable
{
  public function persist()
  {
    apc_store(get_class($this) . $this->id, serialize($this));
  }

  public static function restore($id)
  {
    return unserialize(apc_fetch(get_class($this) . $id));
  }
}

class Book
{
  use Persistable;

  // some methods
}

class Author
{
  use Persistable;

  // some methods
}

Resources:

Vegeu també:

Composition vs Inheritance

Vegeu Composition vs Inheritance

Association

Aggregation

Delegation

Vegeu també

Enllaços externs