domingo, 1 de agosto de 2010

porque y cuando usar interfaces

a continuacion una  serie  de  articulos  que  he e ncontrado en la  red  y  que  permiten entender con mayor claridad el uso de las  interfaces  en la  programacion  para  mejorar  la  calidad de  codigo desarrollado.


este articulo lo encontre en este  foro:http://www.forosdelweb.com/f68/duda-con-interface-php5-440249/
explica claramente  el concepto de interfaz

Interfaces

Una interface es una variante de una clase abstracta con la condición de que todos sus métodos deben ser asbtractos. Si la interface va a tener atributos, éstos deben llevar las palabras reservadas static final y con un valor inicial ya que funcionan como constantes por lo que, por convención, su nombre va en mayúsculas.
interface Nomina
{
 public static final String EMPRESA = "Patito, S. A.";
 public void detalleDeEmpleado(Nomina obj);
}

Una clase implementa una o más interfaces (separadas con comas ",") con la palabra reservada implements. Con el uso de interfaces se puede "simular" la herencia múltiple que Java no soporta.

class Empleado implements Nomina
{
   ...
}
 
una Interfce no puede ser instanciada 





En este ejemplo, la clase Empleado tiene una clase padre llamada Object (implícitamente) e implementa a la interface Nomina, quedando el diagrama de clases de la siguiente manera:


La clase que implementa una interface tiene dos opciones:
1) Implementar todos los métodos de la interface.
2) Implementar sólo algunos de los métodos de la interface pero esa clase debe ser una clase abstracta (debe declararse con la palabra abstract).



Referencias a Interfaces

Es posible crear referencias a interfaces, pero las interfaces no pueden ser instanciadas. Una referencia a una interface puede ser asignada a cualquier objeto que implemente la interface. Por ejemplo:
InstrumentoMusical instrumento = new Guitarra();
instrumento.play();
System.out.prinln(instrumento.tipoInstrumento());

InstrumentoMusical i2 = new InstrumentoMusical(); //error.No se puede instanciar

Extensión de interfaces

Las interfaces pueden extender otras interfaces y, a diferencia de las clases, una interface puede extender más de una interface. La sintaxis es:
interface nombre_interface  extends nombre_interface  , . . . {
    tipo_retorno nombre_metodo ( lista_argumentos ) ;
    . . .
}

Agrupaciones de constantes

Dado que, por definición, todos los datos miembros que se definen en una interface son static y final, y dado que las interfaces no pueden instanciarse resultan una buena herramienta para implantar grupos de constantes. Por ejemplo:
public interface Meses {
    int ENERO = 1 , FEBRERO = 2 . . . ;
    String [] NOMBRES_MESES = { " " , "Enero" , "Febrero" , . . . };
}

Esto puede usarse simplemente:
System.out.println(Meses.NOMBRES_MESES[ENERO]);

Las herencias de clases definen el "qué son" y las de interfaces agrupan clases que definen el "qué hacen".

Cuando agrupas por herencia hay una relación de parentesco, pero con las interfaces agrupas cosas que "hacen cosas similares" como una interfaz "imprimible" que todos tus objetos deberían implementar para poder pasar por la impresora (les estás diciendo de alguna forma que deben cumplir con un "contrato de implementación" para poder ser "imprimibles").

O hacer una interfaz "Pelable" para que la implementen las bananas, las manzanas y tu multiprocesadora. Esta última no es pariente de "frutas", pero puede hacer la misma acción que es "pelar".

Esto se relaciona con el polimorfismo, en el sentido que vas a tener un método de una clase, no sé (ya me estoy divagando mucho), cocinero, que pueda pelar cualquier cosa que le den, mientras estas sean "pelables".


Código PHP:
class Cocinero{
   public function 
pelar($elemento){
      
$elemento->pelar();
   }
}  
El "contrato de implementación" se hace cuando haces este "control de tipo":


Código PHP:
class Cocinero{
   public function 
pelar(Pelable $elemento){
      
$elemento->pelar();
   }
}  
Entonces solo pueden entrar los objetos que cumplan con la interfaz.

Si lo quieres ver de otra forma, se podría hasta decir que las interfaces son una extensión conceptual de la herencia (por lo que puse al principio).

Y finalmente, y esto es clave en entornos como Java, las interfaces permiten pasar del estilo de diseño "orientado a la implementación" a uno "orientado a la interfaz", donde todas las clases acceden a servicios a través de interfaces que son implementadas por clases concretas. Y al no depender de clases concretas (solo de entidades abstractas) nuestro diseño será más reutilizable que el anterior.



este articulo lo encontre en este  blog:http://chuidiang.blogspot.com/2005/10/por-qu-usar-interfaces.html

es muy ilustrativo

Por qué usar interfaces

Una pequeña explicación de por qué usar interfaces al programar. Aunque los ejemplos son java, la idea vale para cualquier lenguaje orientado a objetos.

Imaginemos que hacemos un programa que echa unas cuentas y va presentando en pantalla unos resultados. Puede ser algo como esto

void metodoConLasCuentas()
{
double valor=this.cuentas(datos);
System.out.println ("El valor es "+valor);
double valor2 = this.otrasCuentas(datos);
System.out.println ("El otro valor es " + valor2);
}

Ya está el programa. Se lo enseñamos a nuestro jefe, a nuestro cliente, a nuestro mejor amigo o al gracioso de turno y nos dice ... "Me gustaría poder sacar eso por impresora".

Nos ponemos manos a la obra y cambiamos nuestro programa

void metodoConLasCuentas()
{
double valor=this.cuentas(datos);
this.sacaPorImpresora ("El valor es "+valor);
double valor2 = this.otrasCuentas(datos);
this.sacaPorImpresora ("El otro valor es " + valor2);
}

Volvemos a enseñárselo al graciosillo y nos dice ... "Es que yo querría poder elegir sobre la marcha si lo quiero en pantalla o en impresora".

Nuevamente nos ponemos a tocar el código, pero esta vez algo más complejo

void metodoConLasCuentas()
{
double valor=this.cuentas(datos);

if (porImprsora==true)
this.sacaPorImpresora ("El valor es "+valor);
else
System.out.println ("El valor es "+valor);

double valor2 = this.otrasCuentas(datos);

if (porImpresora==true)
this.sacaPorImpresora ("El otro valor es " + valor2);
else
System.out.println ("El otro valor es " + valor2);
}

Nuevamente el gracios de ideas infinitas nos dice ... "Maravilloso, pero sería bueno poder guardar esos valores en base de datos".

Hartos de tocar el código decidimos implementar una solución que nos valga para todas las peticiones estúpidas del graciosillo. La solución es usar una interface. Hacemos nuestra interface así

interface Escritor
{
public void escribe (String cadena);
}

Ahora hacemos varias clases que implementen la interface, una clase Pantalla con el System.out.println, una clase Impresora con el sacaPorImpresora y una clase ABaseDeDatos con algo que sea capaz de meter esa cadena en la base de datos.

Nuestro código queda así de bonito ahora

void metodoConLasCuentas (Escritor escritor)
{
double valor=this.cuentas(datos);
escritor.escribe ("El valor es "+valor);
double valor2 = this.otrasCuentas(datos);
escritor.escribe ("El otro valor es " + valor2);
}

Llamando a nuestro método pasándole una clase Pantalla, sacará el texto por pantalla, con una clase Impresora, lo sacará por impresora y con un ABaseDeDatos lo guardará en base de datos.

Ya no tenemos que tocar nunca más nuestro código. Únicamente hacernos una nueva clase para la nueva idea del graciosillo y llamar a nuestro método con la nueva clase.

Este es un ejemplo tonto, pero si nos fijamos en java, hay multitud de sitios donde se usa.
  • Un JButton admite una interface ActionListener con un método actionPerformed(). El botón está hecho una única vez para siempre, y pasándole una Interface ActionListener, ese botón hace lo que queramos nosotros. Esta vez la gente de java eran los programadores y nosotros los graciosillos que queremos que el botón haga no sé qué.
  • Un JTable admite una interface TableModel. El TableModel es la interface y somos nosotros los que debemos rellenar los métodos. De esta forma un JTable hecho una sola vez es capaz de pintar cualquier tabla de datos, sin necesidad de tocarla por dentro. Únicamente tenemos que hacernos nuestra clase TableModel y pasársela al JTable.
  • Un Thread admite una interface Runnable. Esta clase Thread es capaz de hacer que se ejecute en un hilo aparte cualquier cosa que nosotros queramos. Únicamente hay que implementar el método run() de la interface Runnable y pasarle eso a la clase Thread.
  • etc, etc, etc.

Este otro texto sacado del msdn de microsoft: http://msdn.microsoft.com/es-es/library/3b5b8ezk(VS.80).aspx
lo complementa perfectamente


Cuándo se deben utilizar interfaces

Las interfaces son una herramienta de programación eficaz porque le permiten separar la definición de objetos de su implementación. La herencia de clases y las interfaces tienen ventajas e inconvenientes, y puede que al final decida utilizar una combinación de ambas en sus proyectos. Esta página y Cuándo utilizar la herencia le ayudarán a determinar qué enfoque es mejor para su situación.

Flexibilidad en la implementación

Existen otras razones por las que se podría desear utilizar interfaces en lugar de la herencia de clases:
  • Las interfaces admiten mejor las situaciones en las cuales las aplicaciones necesitan el mayor número de tipos de objetos no relacionados posible para proporcionar determinadas funciones.
  • Las interfaces son más flexibles que las clases de base, porque puede definir una única implementación que puede implementar interfaces múltiples.
  • Las interfaces son mejores en situaciones en las que no es necesario heredar una implementación de una clase de base.
  • Las interfaces son útiles en casos en los que no se puede utilizar la herencia de clases. Por ejemplo, las estructuras no pueden heredarse de las clases, pero pueden implementar interfaces.

POO: Interfaces, Dependencia de clases y Polimorfismo

La dependencia de clases es un concepto de la programación orientada a objetos que nos indica la relación existente entre dos clases. Como su nombre indica nos está diciendo que una clase depende de otra para realizar su funcionamiento.

Cuando trabajamos con clases es una buena práctica que una clase realice una única función. De manera que las clases que deban realizar funciones complejas estarán formadas a partir de una asociación de diversas pequeñas clases en las que delegará cada funcionalidad en concreto.

Este sería un ejemplo simple de una relación de asociación y de delegación entre clases:

Código :
package 
{
   public class Foro
   {
      private var _moderador:Zguillez;

      public function Foro()
      {
         _moderador = new Zguillez();
      }
      public function moderar():void
      {
         _moderador.moderar();
      }
   }
}


Aqui vemos como la clase "Foro" está delegando toda la funcionalidad del método "moderar" al objeto de clase "Zguillez", haciendo de esta manera que toda la implementación esté en esa clase dejando la clase principal más limpia y ordenada. Esto nos permite una mayor reutilización de nuestras clases.

El problema que nos encontramos aquí es que se ha creado una relación de dependencia muy grande entre estas dos clases. La clase "Foro" tiene una referencia directa a la clase "Zguillez" y necesita estrictamente de esa clase para funcionar.

De manera que si tuviésemos (por requisitos de la aplicación o por reutilización del código) que cambiar la implementación de la función "moderar" tendríamos que reescribir la la clase "Zguillez" para cambiar su implementación concreta o reescribir la clase "Foro" para delegar esa función a la clase "Zah" (por ejemplo). Con lo que hace estas clases poco reutilizables.

Polimorfismo


Esta dependencia la podemos romper gracias al Polimorfismo de las clases. El polimorfismo es la propiedad que tienen las clases de ocultar la estructura interna en una jerarquía de clases, implementando de manera diferente un mismo método. El polimorfismo nos permite que una identificación se refiera a diferentes entidades.

En este caso haremos que "moderador" se pueda referir tanto a "Zguillez" como a "Zah". Este polimorfismo lo podemos conseguir gracias a la herencia de clases o a la implementación de una Interface.

Definiremos una Interface que contendrá las funciones que estamos delegando a la clase asociada. En este caso sería así:

Código :
package 
{
   public interface IModerador
   {
      function moderar():void;
   }
}


Ahora asociaremos el objeto a la Interface en lugar de a una clase en concreto:

Código :
private var _moderador:IModerador;


Tendremos que hacer que tanto la clase "Zguillez" como la clase "Zah" implementen la Interface "IModerador".

Código :
public class Zguillez implements IModerador

Código :
public class Zah implements IModerador


De manera que ahora podemos asociar cualquiera de las dos clases a la propiedad "moderador".

Código :
var moderador:IModerador = new Zguillez();
// o var moderador:IModerador = new Zah();


Gracias al polimorfismo hemos ganado en dinamismo y reutilizabilidad, ya que podemos hacer que nuestra aplicación la "modere" Zguillez o Zah según nos interese.

Pero en este punto aun no nos hemos liberado de la dependencia de clases, ya que la clase que realiza la delegación está escrita en la implementación de la clase. Con lo que si quisiésemos cambiar la clase en la que delegamos tendríamos que reescribir la clase para colocar la otra.

Inyección de dependencias


Esto lo solucionamos con lo que se llama "Inyección de dependencias", que consiste en insertar los objetos a la clase en lugar de que sea la clase la que cree el objeto.

Haremos que la clase "Foro" no genere directamente el objeto que realizará la delegación sino que ese objeto le venga inyectado.

Código :
package 
{
   public class Foro
   {
      private var _moderador:IModerador;

      public function Foro()
      {
      }
      public function set moderador(m:IModerador):void
      {
         _moderador = m;
      }
      public function moderar():void
      {
         _moderador.moderar();
      }
   }
}


Para inyectarle la dependencia utilizaremos el setter.

Código :
var foro:Foro = new Foro();
var moderador:IModerador = new Zguillez();
foro.moderador = moderador;
foro.moderar();


De esta manera hemos conseguido que la clase "Foro" sea totalmente independiente de las clases que vayan a realizar la delegación haciendo el sistema totalmente reutilizable sin tener que realizar cambios en las clases existentes.

No hay comentarios:

Publicar un comentario

escribe tu opinion: