Ver Mensaje Individual
  #6 (permalink)  
Antiguo 08/09/2014, 18:32
Avatar de hhs
hhs
Colaborador
 
Fecha de Ingreso: junio-2013
Ubicación: México
Mensajes: 2.995
Antigüedad: 11 años, 5 meses
Puntos: 379
Respuesta: Diferencia entre clase Abstracta y interfaz

Ya con un poco mas de tiempo he decidido ampliar un poco este hilo para aclarar la duda de juan14_nob y que considero es una duda común.

Cita:
¿Herede o Implemente va a ser lo mismo?
No, no es lo mismo las interfaces y las clases abstractas son conceptos diferentes

Cita:
Una interfaz es la descripción de las acciones que puede realizar un objeto
Cita:
Una clase abstracta es aquella cuyo propósito principal es definir una interfaz común para sus subclases.
La interfaz describe un objeto desde afuera o si lo prefieres su abstracción es decir; una interfaz (abstracción de un objeto) te dice lo que puede hacer un objeto sin conocer su detalles internos.
Para fines prácticos esto quieres decirr que cuando modelo un objeto en PHP puedo declarar la abstracción mediante la interfaz y además su comportamiento interno mediante una clase.
En otras palabras un objeto en un lenguaje puede ser definido de la siguiente forma

Cita:
Objeto = interfaz (abtracción) + su clase (implementación)
Las clases abstractas es el equivalente de una interfaz pero para una jerarquía de objetos, como es la abstracción del comportamiento de una jerarquía no se pueden instanciar directamente. Un ejemplo del mundo real lo puedes apreciar en los smartphone todos comparte características y funcionalidad similares, pero cuando usas uno no tienes un objeto smartphone, si no mas bien un objeto concreto del tipo smart phone (Samsung GT-E1205, LG D950-G Flex, etc.)

Ahora vamos a traducir todo esto a un ejemplo en PHP, para esto voy a usar una definición de reloj y vamos a modelarlo de forma muy sencilla para centrarnos en los conceptos que mencione antes.

Cita:
Reloj (objeto) : Instrumento para medir el tiempo o para indicar la hora del día (lo que hace); puede ser fijo o portátil y el más común para indicar la hora consiste en una maquinaria de movimientos uniformes que hace avanzar unas manecillas sobre una superficie esférica, marcando el paso del tiempo.
De la definición se puede determinar que la razón de ser de un reloj es proporcionarme la hora del día. Claro esta que también conocemos por experiencia que puede proporcionarnos la fecha actual entre otras cosas. Pero como lo comente vamos a dejarlo sencillo, así que podemos representar la abstracción de un reloj de la siguiente forma en php.

Código PHP:
Ver original
  1. interface Reloj
  2. {
  3.     public function hora();
  4. }
Con la interfaz estoy declarando las posibles variantes que puede tener un objeto Reloj y lo útil de esto es que puedo usar la interfaz antes de haber escrito siquiera una clase concreta de reloj. Para esto crearemos una persona que pueda usar un reloj de cualquier tipo.
Código PHP:
Ver original
  1. class Persona {
  2.     private $reloj;
  3.  
  4.     public function usar(Reloj $reloj){
  5.         $this->reloj = $reloj;
  6.  
  7.         return $this;
  8.     }
  9.  
  10.     public function verLaHora(){
  11.         return 'Reloj: '.get_class($this->reloj).' Hora: '.$this->reloj->hora();
  12.     }
  13. }

Para probar la utilidad de la interfaz voy a crear diferentes relojes que me proporcionen la hora y la fecha en diferentes formatos.

  • Formato de 12 horas
  • Formato de 12 horas y fecha
  • Formato de 12 o 24 horas
  • Formato configurable de 12 o 24 horas y formato de fecha configurable
Código PHP:
Ver original
  1. class RelojDePared implements Reloj{
  2.  
  3.     // formato de 12 horas
  4.     public function hora()
  5.     {
  6.         return date('h:i:s a');
  7.     }
  8. }
  9.  
  10. class RelojPuslsoClasico implements Reloj {
  11.  
  12.     private $dateTime;
  13.  
  14.     public function __construct()
  15.     {
  16.         $this->dateTime = new DateTime();
  17.     }
  18.  
  19.     //formato de 12 horas y fecha del día
  20.     public function hora()
  21.     {
  22.         return $this->dateTime->format('h:i:s A, d M y');
  23.     }
  24. }
  25.  
  26. class RelojPulsoDigital implements Reloj {
  27.     private $dateTime;
  28.  
  29.     private $formato = [
  30.         12 => 'h:i:s a',
  31.         24 => 'H:i:s'
  32.     ];
  33.  
  34.     private $formatoHora;
  35.  
  36.     public function __construct($formatoHora = 12)
  37.     {
  38.         $this->dateTime = new DateTime();
  39.         $this->formatoHora = $formatoHora;
  40.     }
  41.  
  42.     //formato de 12 o 24 horas
  43.     public function hora()
  44.     {
  45.         return $this->dateTime->format($this->formato[$this->formatoHora]);
  46.     }
  47. }
  48.  
  49. class RelojDigitalConCalendario implements Reloj{
  50.  
  51.     private $dateTime;
  52.  
  53.     private $formatoHora;
  54.  
  55.     private $formatoFecha;
  56.  
  57.     public function __construct($formatoHora = 'h:i:s a', $formatoFecha = 'Y-m-d')
  58.     {
  59.         $this->dateTime = new DateTime();
  60.         $this->formatoHora = $formatoHora;
  61.         $this->formatoFecha = $formatoFecha;
  62.     }
  63.  
  64.     // formato de 12 o 24 hrs y fecha del día
  65.     public function hora()
  66.     {
  67.         return $this->dateTime->format(
  68.             sprintf('%s %s', $this->formatoHora, $this->formatoFecha)
  69.         );
  70.     }
  71. }


Creamos instancias de cada reloj y probamos que las use Persona:

Código PHP:
Ver original
  1. $relojPared = new RelojDePared();
  2. $relojClasico = new RelojPuslsoClasico();
  3. $relojDigital = new RelojPulsoDigital();
  4. $relojDigital24 = new RelojPulsoDigital(24);
  5. $relojDigitalConCalendario = new RelojDigitalConCalendario();
  6. $mejorReloj = new MejoraRelojDigital();
  7.  
  8.  
  9. $persona = new Persona();
  10. echo $persona->usar($relojPared)->verLaHora() .'<br>';
  11. echo $persona->usar($relojClasico)->verLaHora() .'<br>';
  12. echo $persona->usar($relojDigital24)->verLaHora() .'<br>';
  13. echo $persona->usar($relojDigital)->verLaHora() .'<br>';
  14. echo $persona->usar($relojDigitalConCalendario)->verLaHora() .'<br>';


Si te das cuenta todas las clases hace su trabajo interno de forma diferente pero como están implementando la interfaz Reloj esto no marcara diferencia alguna para el objeto persona que puede usar cualquiera de los relojes que implementamos.

Hasta aquí espero que ya este claro el concepto de interfaz. Para tratar el tema de clase abstracta vamos a emplear lo que ya tenemos echo.
Si te das cuenta algunos de las implementaciones de los relojes comparten casi el mismo código lo único diferente es el formato que entregan.

Si seguimos agregando implementaciones puede llegar un punto en el que tengamos varias clases repitiendo el mismo código así que puedes agruparlo y no estarlo repitiendo. Así que crearemos una clase abstracta que contenga ese código que puede extenderse para implementar nuevos relojes.
Código PHP:
Ver original
  1. abstract class AbstractReloj implements Reloj {
  2.  
  3.     protected  $dateTime;
  4.  
  5.     protected  $formatoHora;
  6.  
  7.     protected  $formatoFecha;
  8.  
  9.     public function __construct($formatoHora = 'h:i:s a', $formatoFecha = 'Y-m-d')
  10.     {
  11.         $this->dateTime = new DateTime();
  12.         $this->formatoHora = $formatoHora;
  13.         $this->formatoFecha = $formatoFecha;
  14.     }
  15.     public function hora()
  16.     {
  17.       return $this->dateTime->format($this->formato());
  18.     }
  19.  
  20.     abstract public function formato();
  21.  
  22. }
  23.  
  24. class MejoraRelojDigital extends AbstractReloj{
  25.  
  26.     // formato 12 o 24 horas y fecha del día
  27.     public function formato()
  28.     {
  29.         return sprintf('[ %s, %s ]',$this->formatoHora, $this->formatoFecha);
  30.     }
  31. }


Probamos nuestro cambio nuevamente
Código PHP:
Ver original
  1. $mejorReloj = new MejoraRelojDigital();
  2. $persona = new Persona();
  3. echo $persona->usar($mejorReloj)->verLaHora() .'<br>';


Si hiciste la prueba puedes apreciar que el reloj funciono sin ningún problema. La utilidad de las interfaces y las clases abstractas es que te permiten crear código mas flexible a los cambios, y eso lo pueden notar en que hicimos diferentes objetos y en cada caso no tuvimos que cambiar al objeto persona para que nuestro código siguiera funcionando.


El ejemplo es sencillo pero espero que con esto se aclare un poco la diferencia entre las interfaces y las clases abstractas lo siguiente es que experimentes con ellas.
__________________
Saludos
About me
Laraveles
A class should have only one reason to change.