15
08/06/2015 1 Lic. Ariel Trellini Departamento de Ciencias e Ingeniería de la Computación Universidad Nacional del Sur Arquitectura y Diseño de Sistemas 2 Lic. Ariel Trellini • DCIC • UNS Prácticas de Diseño Desacoplando

Prácticas de Diseño - cs.uns.edu.arcs.uns.edu.ar/~atrellini/ayds/downloads/Clases/17. AyDS - Practicas...facilitando el testeo de otras clases y permitiendo que múltiples equipos

  • Upload
    vodang

  • View
    218

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Prácticas de Diseño - cs.uns.edu.arcs.uns.edu.ar/~atrellini/ayds/downloads/Clases/17. AyDS - Practicas...facilitando el testeo de otras clases y permitiendo que múltiples equipos

08/06/2015

1

Lic. Ariel Trellini

Departamento de Ciencias e Ingeniería de la ComputaciónUniversidad Nacional del Sur

Arquitectura y Diseño de Sistemas • 2 Lic. Ariel Trellini • DCIC • UNS

Prácticas de Diseño

Desacoplando

Page 2: Prácticas de Diseño - cs.uns.edu.arcs.uns.edu.ar/~atrellini/ayds/downloads/Clases/17. AyDS - Practicas...facilitando el testeo de otras clases y permitiendo que múltiples equipos

08/06/2015

2

Arquitectura y Diseño de Sistemas • 3 Lic. Ariel Trellini • DCIC • UNS

Programando a Interfaces

Prácticas de Diseño

¿Quién puede definir qué es una interfaz?

Una interfaz es el contrato entre una clase y el mundo exterior.

Cuando una clase implementa una interfaz, promete proveer el

comportamiento indicado por la interfaz.

Ejemplo: Interfaz e implementación de un Logger

Arquitectura y Diseño de Sistemas • 4 Lic. Ariel Trellini • DCIC • UNS

Consideraciones

Implementar una interfaz le permite ser más formal a una clase al definir el comportamiento que se compromete a proveer.

Una interfaz constituye el contrato entre la clase que la implementa y el mundo exterior, y este contrato es forzado en tiempo de compilación.

Una interfaz establece “qué” hace un objeto, en vez de “cómo” lo hace.

Una interfaz define el vocabulario puro de una colaboración, ya que no se ensucia con detalles de implementación. Una vez que entendemos las interfaces, entendemos la colaboración.

Prácticas de Diseño Programando a Interfaces

Page 3: Prácticas de Diseño - cs.uns.edu.arcs.uns.edu.ar/~atrellini/ayds/downloads/Clases/17. AyDS - Practicas...facilitando el testeo de otras clases y permitiendo que múltiples equipos

08/06/2015

3

Arquitectura y Diseño de Sistemas • 5 Lic. Ariel Trellini • DCIC • UNS

Diferencias entre Interfaces y Clases Abstractas

Prácticas de Diseño Programando a Interfaces

Característica Interfaz Clase Abstracta

Herencia múltiple Una clase puede implementar varias interfaces

Una clase puede heredar de solamente una clase abstracta

Implementación por defecto

No provee comportamiento, sólo la firma de los métodos.

Podría proveer comportamiento por defecto para los métodos.

Modificadores de acceso

No se pueden definir modificadores de acceso

Puede tener modificadores de acceso para todos sus miembros.

Impronta Define las capacidades de una clase.

Define la identidad central de una clase. Es usada por objetos del mismo tipo.

Extensibilidad Si se agrega una feature, hay que modificar la clase concreta.

Si se agrega una feature, se podría proveer una implementación por defecto y así, todo sigue funcionando.

Variables de instancia y constantes

No Sí

Arquitectura y Diseño de Sistemas • 6 Lic. Ariel Trellini • DCIC • UNS

Prácticas de Diseño Programando a Interfaces

¿Qué significaría Programar a Interfaces?

Programar a interfaces, no a clases. Esto desacopla las interfaces

de sus implementaciones. Disminuir el acoplamiento entre

objetos promueve la flexibilidad.

“Programar a una interfaz, no a una implementación” es un principio acuñado en el libro Design Patterns: Elements of Reusable Object-Oriented Software (GoF).

Apunta a las relaciones de dependencia que tienen que ser cuidadosamente manejadas en una aplicación de mediana/gran escala.

Es muy fácil agregarle una dependencia a una clase. Sin embargo, deshacerse de una dependencia no deseada puede generar un trabajo de refactoring pesado o aun peor, puede evitar que se reuse código

Page 4: Prácticas de Diseño - cs.uns.edu.arcs.uns.edu.ar/~atrellini/ayds/downloads/Clases/17. AyDS - Practicas...facilitando el testeo de otras clases y permitiendo que múltiples equipos

08/06/2015

4

Arquitectura y Diseño de Sistemas • 7 Lic. Ariel Trellini • DCIC • UNS

Ventajas La posibilidad de cambiar la clase de implementación de cualquier

componente de la aplicación sin afectar al código cliente.

Esto permite parametrizar cualquier parte de la aplicación sin romper otros componentes

Libertad total para implementar interfaces. No hay necesidad de acoplarse a una jerarquía de herencia.

Sin embargo, aun es posible reusar código, utilizando herencias concretas en la implementación de una interfaz.

La capacidad de proveer stubs/mocks simples que implementen interfaces, facilitando el testeo de otras clases y permitiendo que múltiples equipos trabajen en paralelo luego que acuerdan las interfaces.

Facilita la definición de la API publicada

Vale distinguir entre la API pública de un componente (clases, métodos y propiedades públicas) y la API publicada que es la que debe ser usada por los clientes del componente.

Prácticas de Diseño Programando a Interfaces

Arquitectura y Diseño de Sistemas • 8 Lic. Ariel Trellini • DCIC • UNS

Consideraciones No es necesario tener el diseño de interfaces completo antes de comenzar

a codificar. Se puede comenzar con clases concretas e ir descubriendo las interfaces una vez que se tenga un conocimiento pormenorizado del problema.

No significa que hay que escribir una interfaz para cada clase. Criterio posible:

La API de un componente es una excelente candidata

Clases que podrían variar su implementación

Clases que necesitan mockearse para testear a sus clientes.

No es forzoso el uso de interfaces. Las clases abstractas también podrían servir para cumplir con el objetivo.

Provee más flexibilidad en la evolución. Podemos agregar un método a una clase abstracta proveyendo un comportamiento por defecto. Todo esto, sin romper el contrato.

Puede combinarse. Exponer una interfaz e implementarla con una jerarquía de clases.

Prácticas de Diseño Programando a Interfaces

Page 5: Prácticas de Diseño - cs.uns.edu.arcs.uns.edu.ar/~atrellini/ayds/downloads/Clases/17. AyDS - Practicas...facilitando el testeo de otras clases y permitiendo que múltiples equipos

08/06/2015

5

Arquitectura y Diseño de Sistemas • 9 Lic. Ariel Trellini • DCIC • UNS

Ejemplo: Componente para envío de e-mails

Prácticas de Diseño Programando a Interfaces

Arquitectura y Diseño de Sistemas • 10 Lic. Ariel Trellini • DCIC • UNS

Ejemplo: Componente para envío de e-mails (cont)

Prácticas de Diseño Programando a Interfaces

Interfaz Descripción Implementación Descripción

IMailFactory Encargada de la creación de un Nuevo e-mail. Es parte de la interfaz pública del componente

DotNetMailFactory Crea instancias de DotNetMail

IMail Interfaz fluent sobre la que se completan todos los datos del e-mail a enviar. También forma parte de la interfaz pública.

DotNetMail Utiliza System.Net.Mailcomo API subyacente

IMailConfigFactory Se encarga de obtener la configuración del componente.

ConfigSectionMailConfigFactory

Obtiene la configuración desde una sección del web/app.config

IMailConfig Representación de la configuración del componente

MailConfigSection Representación de la sección de configuración.

ITemplateFactory Se encarga de obtener la definición de un template de acuerdo a su nombre

TemplateFactory Recupera los templates de la configuración y el sistema de archivos.

Page 6: Prácticas de Diseño - cs.uns.edu.arcs.uns.edu.ar/~atrellini/ayds/downloads/Clases/17. AyDS - Practicas...facilitando el testeo de otras clases y permitiendo que múltiples equipos

08/06/2015

6

Arquitectura y Diseño de Sistemas • 11 Lic. Ariel Trellini • DCIC • UNS

Ejemplo: Componente para envío de e-mails (cont)

Prácticas de Diseño Programando a Interfaces

Interfaz Descripción Implementación Descripción

IContentRenderer Se encarga de renderizar un template de e-mail inyectando los datos del modelo

RazorRenderer Renderiza los templates utilizando RazonEngine.

IMailManager Componente de negocio que provee métodos para cada una de las situaciones de envío de mail.

MailManager Utiliza el componente de envío de mails para implementar el envío de los mails necesarios por la aplicación

Arquitectura y Diseño de Sistemas • 12 Lic. Ariel Trellini • DCIC • UNS

Inversión de Control

Ejemplo Command Line (sin IoC)

Prácticas de Diseño

El flujo de control no es manejado por nuestro código, sino existe

un framework que decide cuándo invocar a nuestro código.

El control está en nuestro código

Page 7: Prácticas de Diseño - cs.uns.edu.arcs.uns.edu.ar/~atrellini/ayds/downloads/Clases/17. AyDS - Practicas...facilitando el testeo de otras clases y permitiendo que múltiples equipos

08/06/2015

7

Arquitectura y Diseño de Sistemas • 13 Lic. Ariel Trellini • DCIC • UNS

Ejemplo (cont.) .Net Win-Forms (con IoC)

Prácticas de Diseño Inversión de Control

El control lo tiene el framework en el que implementamos el formulario.

Arquitectura y Diseño de Sistemas • 14 Lic. Ariel Trellini • DCIC • UNS

Prácticas de Diseño Inversión de Control

Una característica importante de un framework es que los

métodos definidos por el usuario para adaptarlo (tailoring) a su

problemática, generalmente son llamados desde dentro del

framework, más bien que desde el código de la aplicación del

usuario.

El framework generalmente juega el rol de “programa

principal”, coordinando y secuenciando la actividad de la

aplicación. Esta inversión de control les da a los frameworks el

poder de servir como esqueletos extensibles. Los métodos

suministrados por el usuario adaptan los algoritmos genéricos

definidos en el framework a una aplicación particular.

Ralph Johnson and Brian Foote

Page 8: Prácticas de Diseño - cs.uns.edu.arcs.uns.edu.ar/~atrellini/ayds/downloads/Clases/17. AyDS - Practicas...facilitando el testeo de otras clases y permitiendo que múltiples equipos

08/06/2015

8

Arquitectura y Diseño de Sistemas • 15 Lic. Ariel Trellini • DCIC • UNS

Consideraciones No es un concepto nuevo.

Se comenzó a tratar en 1988, en un artículo Designing Reusable Classes, de Ralph E. Johnson y Brian Foote.

Es una característica intrínseca de los framewoks.

Inversión de Control es una parte clave de lo que hace a un framework diferente de una librería.

Una librería es, esencialmente, un conjunto de funciones que se invocan. Cada llamada realiza algún trabajo y luego retorna el control al cliente.

Un framework encapsula un diseño abstracto. Para usarlo, se debe insertar comportamiento en distintos lugares del framework, ya sea por herencia o por plug-ins. De esta manera, el código del framework llama a nuestro comportamiento.

También se lo conoce como Principio de Hollywood

No nos llames… nosotros te llamamos.

No debe confundirse con Inyección de Dependencias (DependencyInjection), que es un tipo especial de Inversión de Control.

Prácticas de Diseño Inversión de Control

Arquitectura y Diseño de Sistemas • 16 Lic. Ariel Trellini • DCIC • UNS

Ejemplos Conocidos UI Frameworks

Window Forms

Swing

Tecnologías web

Páginas ASP.NET

ASP.NET MVC

JSF

EJBs

Template Methods

Una superclase define el flujo de control a través de un Template Method.

Las sub-clases extienden o implementan los métodos abstractos de la superclase.

Frameworks de testing unitario automático

JUnit

NUnit

Etcéteras.

Prácticas de Diseño Inversión de Control

Page 9: Prácticas de Diseño - cs.uns.edu.arcs.uns.edu.ar/~atrellini/ayds/downloads/Clases/17. AyDS - Practicas...facilitando el testeo de otras clases y permitiendo que múltiples equipos

08/06/2015

9

Arquitectura y Diseño de Sistemas • 17 Lic. Ariel Trellini • DCIC • UNS

Inyección de Dependencias

Prácticas de Diseño

SHOWTIME !Refactoring hacia Inyección de Dependencias.

Sin Inyección de Dependencias Con Inyección de Dependencias

Dependiente (PeliculasService) Dependencias (PeliculasRepository) Provider (Ensamblador)

Participantes:

Arquitectura y Diseño de Sistemas • 18 Lic. Ariel Trellini • DCIC • UNS

Objetivos Eliminar la lógica de gestión del ciclo de vida de las dependencias

Desacoplar las clases de sus dependencias concretas

Idea Básica Convencionalmente, si un objeto (Dependiente) necesita de otro

(Dependencia) para realizar una tarea particular, será responsable de instanciarlo y (eventualmente) liberarlo, lo cual agrega cierta complejidad adicional al objeto Dependiente.

Con Inyección de Dependencias, el objeto Dependiente es provisto de sus Dependencias, moviendo el código relacionado con el ciclo de vida de las Dependencias a un lugar más apropiado.

El Ensamblador se encarga de resolver las dependencias entre los componentes de la aplicación.

Prácticas de Diseño Inyección de Dependencias

Es un tipo específico de Inversión de Control donde el aspecto de

control que se invierte es el de resolución de dependencias.

Martin Fowler

Page 10: Prácticas de Diseño - cs.uns.edu.arcs.uns.edu.ar/~atrellini/ayds/downloads/Clases/17. AyDS - Practicas...facilitando el testeo de otras clases y permitiendo que múltiples equipos

08/06/2015

10

Arquitectura y Diseño de Sistemas • 19 Lic. Ariel Trellini • DCIC • UNS

Tipos de Inyección de Dependencias

Inyección por Interfaz (Tipo 1) Cada dependencia provee una interfaz que su usuario tiene que

implementar para obtener la dependencia en ejecución.

Prácticas de Diseño Inyección de Dependencias Tipos

Interface Injection

Arquitectura y Diseño de Sistemas • 20 Lic. Ariel Trellini • DCIC • UNS

Inyección por Setter (Tipo 2) El dependiente provee un método “setter” el cual el ensamblador utiliza

para inyectarle la dependencia.

Inyección por Constructor (Tipo 3) Las dependencias son inyectadas a través del constructor de la clase.

Prácticas de Diseño Inyección de Dependencias Tipos

Page 11: Prácticas de Diseño - cs.uns.edu.arcs.uns.edu.ar/~atrellini/ayds/downloads/Clases/17. AyDS - Practicas...facilitando el testeo de otras clases y permitiendo que múltiples equipos

08/06/2015

11

Arquitectura y Diseño de Sistemas • 21 Lic. Ariel Trellini • DCIC • UNS

Contenedor de Inyección de Dependencias

¿Por qué Container y no Factory? Los Containers toman más responsabilidades que sólo instanciar los objetos

e inyectar sus dependencias.

Alcance del objeto: Singleton, Transient, , etc.

Inicializar y liberar.

Etc.

El Container eventualmente se queda con una referencia al objeto creado (para singletons y flyweights).

Prácticas de Diseño Inyección de Dependencias Contenedor

Implementa el Ensamblador del patrón Dependency Injection. Se

encarga de manejar el ciclo de vida de los objetos administrados

por el container: instanciar, configurar, resolver dependencias,

liberar.

Arquitectura y Diseño de Sistemas • 22 Lic. Ariel Trellini • DCIC • UNS

Ejemplos .NET:

Unity

Spring.NET

Ninject

Castle Windsor

Java

Spring Framework

Guice

PicoContainer

HiveMind

Dependency Injection for Java (API reference)

Avalon

PHP

Symfony

Bucket

Pimple

Prácticas de Diseño Inyección de Dependencias Contenedor

Page 12: Prácticas de Diseño - cs.uns.edu.arcs.uns.edu.ar/~atrellini/ayds/downloads/Clases/17. AyDS - Practicas...facilitando el testeo de otras clases y permitiendo que múltiples equipos

08/06/2015

12

Arquitectura y Diseño de Sistemas • 23 Lic. Ariel Trellini • DCIC • UNS

Service Locator

Prácticas de Diseño Inyección de Dependencias Service Locator

Es un objeto que conoce como obtener referencias a cada

componente de la aplicación.

Martin Fowler

Arquitectura y Diseño de Sistemas • 24 Lic. Ariel Trellini • DCIC • UNS

Ejemplos

Uso en conjunción con un DI container Cuando se necesita una instancia manejada por el container desde un

objeto no manejado por el container.

Cuando se requiere una nueva instancia de una dependencia en cada invocación, y el objeto dependiente tiene un ciclo de vida mayor.

Prácticas de Diseño Inyección de Dependencias Service Locator

Page 13: Prácticas de Diseño - cs.uns.edu.arcs.uns.edu.ar/~atrellini/ayds/downloads/Clases/17. AyDS - Practicas...facilitando el testeo de otras clases y permitiendo que múltiples equipos

08/06/2015

13

Arquitectura y Diseño de Sistemas • 25 Lic. Ariel Trellini • DCIC • UNS

Consideraciones

Service Locator (SL) vs Inyección de Dependencias (DI) Ambos proveen el desacoplamiento básico: El objeto dependiente es

agnóstico de la implementación de la dependencia.

La gran diferencia entre los dos patrones es la forma en que la instancia concreta de la dependencia es suministrada al objeto dependiente:

Con SL, la clase dependiente necesita interpelar explícitamente al SL para recuperar la instancia.

Con DI, no hay un requerimiento explícito, sino la dependencia aparece seteadaen el objeto dependiente, gracias a DI.

DI hace más explícito el reconocimiento de las dependencias.

DI puede introducir cierta complejidad adicional a la de un SL.

SL requiere que la clase dependiente tenga una referencia al SL.

Ambos facilitan el testing, aunque DI lo hace de manera más explícita.

Prácticas de Diseño Inyección de Dependencias Consideraciones

Arquitectura y Diseño de Sistemas • 26 Lic. Ariel Trellini • DCIC • UNS

Consideraciones (cont.)

Inyección por Setter (SI) vs Inyección por Constructor (CI) La elección entre estas dos Tipos de DI es interesante ya que atiende un

poblema más general de la POO: ¿Las propiedades de un objeto debieranllenarse en un constructor o a través de setters?

CI permite crear objetos válidos desde su concepción

CI permite ocultar cualquier propiedad que sea inmutable, no proveyendoel setter para la misma.

Si la cantidad de dependencias de un objeto es muy elevada, convendríautilizar SI, ya que mejoraría la legibilidad de la clase.

Con SI cada setter tiene un nombre que representa a la propiedad en cuestión. Con CI, muchas veces se debe confiar en la posición del parámetro.

Prácticas de Diseño Inyección de Dependencias Consideraciones

Page 14: Prácticas de Diseño - cs.uns.edu.arcs.uns.edu.ar/~atrellini/ayds/downloads/Clases/17. AyDS - Practicas...facilitando el testeo de otras clases y permitiendo que múltiples equipos

08/06/2015

14

Arquitectura y Diseño de Sistemas • 28 Lic. Ariel Trellini • DCIC • UNS

Beneficios Desacopla los componentes de sus dependencias concretas

DI hace posible eliminar, o al menos reducir, las dependencias innecesarias sobre un componente.

Retrasa la resolución de dependencias Las dependencias se resuelven en tiempo de configuración o de ejecución.

Código más reusable Reducir las dependencias entre componentes generalmente facilita el reuso

de los componentes en otros contextos.

El hecho que las dependencias puedan ser inyectadas y configuradasexternamente, incrementa la reusabilidad de un componente.

Código más testeable Cuando se inyectan dependencias en un componente, es posible inyectar

mocks/stubs de estas dependencias

Prácticas de Diseño Inyección de Dependencias Beneficios

Arquitectura y Diseño de Sistemas • 29 Lic. Ariel Trellini • DCIC • UNS

Beneficios (Cont.)

Código Más Legible DI mueve las dependencias a la interfaz del componente. Esto facilita ver

qué dependencias tiene un componente.

Acarreo de Dependencias Reducido El acarreo de dependencias se manifiesta cuando un objeto tiene un

parámetro en uno de sus método que no usa para nada. Sin embargo, lo necesita para crear a una de sus dependencias.

DI elimina este acarreo dependencias.

Promueve la Programación a Interfaces

Favorece el desarrollo de arquitecturas pluggeables.

Prácticas de Diseño Inyección de Dependencias Beneficios

Page 15: Prácticas de Diseño - cs.uns.edu.arcs.uns.edu.ar/~atrellini/ayds/downloads/Clases/17. AyDS - Practicas...facilitando el testeo de otras clases y permitiendo que múltiples equipos

08/06/2015

15

Arquitectura y Diseño de Sistemas • 30 Lic. Ariel Trellini • DCIC • UNS

Problemas

El uso excesivo puede aumentar la complejidad de las aplicaciones.

Puede dificultar el mantenimiento de las aplicaciones

Anarquía de configuración

Prácticas de Diseño Inyección de Dependencias Problemas