Patrones utiles para solid

Preview:

Citation preview

noviembre de 2011

Patrones útiles para los principios SOLID

Dept. Tecnologias Corporativas

José Miguel TorresArea I+D+i

• Básicos• Fundamentos• Principios• Patrones

• Aspectos• Acoplamiento• Cohesión• Encapsulamiento

• Principios SOLID• SRP• OCP• LSP• DIP• ISP

• Reflexión

Agenda

Acoplamiento

Cohesión

Encapsulamiento

Principios SOLID

SRP - Single Responsibility Principle

OCP - Open Closed Principle

LSP - Liskov Substitution Principle

DIP - Dependency Inversion Principle

ISP - Interface Segregation Principle

Principio de Responsabilidad Únicapublic class Factura

{

public string _codigo;

public DateTime _fechaEmision;

public decimal _importeFactura;

public decimal _importeIVA;

public decimal _importeDeducir;

public decimal _importeTotal;

public ushort _porcentageDeduccion;

//método que calcula el Total de la factura

public void CalcularTotal()

{

//Calculamos la deducción_importeDeducir = (_importeFactura*_porcenDeduccion)

/100;

//Calculamos el IVA

_importeIVA = _importeFactura * 0.16m;

//calculamos el total

_importeTotal = (_importeFactura - _importeDeducir)

+ _importeIVA;

}

}

Principio de Responsabilidad Única

Una clase debe tener una y sólo una única causa por la cual puede ser modificadaRobert C. Martin

Principio de Responsabilidad Única//clase IVA que calcula el iva en base a un importe

public class IVA {

public readonly decimal _iva = 0.16m;

public decimal CalcularIVA(decimal importe){

return importe*_iva;}

}

//clase deduccion que calcula la deducción en base a un importepublic class Deduccion {

public readonly decimal _deduccion;

public Deduccion(ushort porcentage){

_deduccion = porcentage; }

public decimal CalcularDeduccion(decimal importe){

return (importe*_deduccion)/100;}

}

Principio de Responsabilidad Únicapublic class Factura{

public string _codigo;public DateTime _fechaEmision;

public decimal _importeFactura;public decimal _importeIVA;public decimal _importeDeducir;public decimal _importeTotal;public ushort _porcentageDeduccion;

public void CalcularTotal(){

//calculamos el IVAIVA iva = new IVA();_importeIVA = iva.CalcularIVA(_importeFactura);

//calculamos la deducción a aplicarDeduccion deduccion = new Deduccion(_porcentageDeduccion);_importeDeducir = deduccion.CalcularDeduccion(_importeFactura);

//calculamos el total_importeTotal = (_importeFactura - _importeDeducir) + _importeIVA;

}}

Principio de Responsabilidad Única

interface Modem{void dial(int pNumber);void hangup();void send(char[] data);char[] receive();

}

Patrón Software

Patrón Software

Principio Open/Closedpublic void Finalizar()

{

switch (_estadoTarea)

{

case TareasEstadosEnum.Pendiente:

//finalizamos

break;

case TareasEstadosEnum.Finalizada:

throw new

ApplicationException

("Ya esta finalizada");

case TareasEstadosEnum.Cancelada:

throw new

ApplicationException

("Imposible finalizar. Tarea cancelada");

default:

throw new ArgumentOutOfRangeException();

}

}

Principio Open/Closed

public void Finalizar()

{

switch (_estadoTarea)

{

case TareasEstadosEnum.Pendiente:

//finalizamos

break;

case TareasEstadosEnum.Finalizada:

throw new ApplicationException("Ya esta finalizada");

case TareasEstadosEnum.Cancelada:

throw new ApplicationException("Imposible finalizar. Tarea cancelada");

case TareasEstadosEnum.Pospuesta:

throw new ApplicationException("Imposible finalizar. Tarea no completada");

default:

throw new ArgumentOutOfRangeException();

}

Principio Software

Principio Software

Principio Open/Closed

Una clase debe estar abierta a extensiones pero cerrada

a las modificaciones.Dr. Bertrand Meyer

Fundamentos OO Encapsulamiento

class EstadosTareas

{

public virtual void Finalizar(EstadoTareasEnum estadoTareasEnum)

{

switch (estadoTareasEnum) {

case EstadoTareasEnum.Pendiente:

//finalizamos

case EstadoTareasEnum.Pospuesta:

throw new ApplicationException("Imposible finalizar. Tarea no completada");

. . . .default:

throw new ArgumentOutOfRangeException();

}

}

public virtual void Cancelar(EstadoTareasEnum estadoTareasEnum)

{

switch (estadoTareasEnum){

. . . .//cancelamos

}

}

public virtual void Posponer(EstadoTareasEnum estadoTareasEnum)

{

switch (estadoTareasEnum){

. . . .//posponemos

}

}

}

Fundamentos OO Polimorfismo

abstract class EstadosTareasBase {

protected Tareas _tarea;

public abstract void Finalizar();

public abstract void Cancelar();

public abstract void Posponer();

}

class EstadoTareaPendiente : EstadosTareasBase {

public override void Finalizar()

{

//finalizamos

}

public override void Cancelar()

{

//cancelamos

}

public override void Posponer()

{

//posponemos

}

}

Fundamentos OO Polimorfismo

class Tareas

{

private EstadosTareasBase _estadosTareas;

public Tareas()

{

_estadosTareas = new EstadoTareaPendiente();

}

public void Finalizar()

{

_estadosTareas.Finalizar();

}

public void Cancelar()

{

_estadosTareas.Cancelar();

}

public void Posponer()

{

_estadosTareas.Posponer();

}

}

Patrón Software

Patrón Software

Principio de Substitución de Liskovclass Ciclomotor: Vehiculo

{

public string ObtenerNumLicencia()

{

//devuelve num licencia

}

}

class Coche: Vehiculo

{

public string ObtenerMatricula()

{

//devuelve matricula

}

}

class Impuestos

{

public void CalcularImpuesto(Vehiculo vehiculo)

{

string matricula = ((Coche) vehiculo).ObtenerMatricula();

ServicioCalculoImpuestos(matricula, vehiculo.Cilindrada);

}

}

Principio de Substitución de Liskov

Si por cada objeto o1 del tipo S existe un objeto o2 del tipo T

tal que para todos los programas P definidos en términos de T y el comportamiento de P

permanece invariable cuando o1 es sustituido por o2, entonces S es un subtipo de T.

Barbara Liskov

Principio de Substitución de Liskov

public void CalcularImpuesto(Vehiculo vehiculo)

{

string matricula = string.Empty;

if (vehiculo.GetType().Name == "Coche")

matricula = ((Coche) vehiculo).ObtenerMatricula();

else if (vehiculo.GetType().Name == "Ciclomotor")

matricula = ((Ciclomotor)vehiculo).ObtenerNumLicencia();

ServicioCalculoImpuestos(matricula, vehiculo.Cilindrada);

}

Principio de Substitución de Liskovpublic class Cuadrado : Rectangulo

{

public override int Ancho

{

get

{

return base.Ancho;

}

set

{

base.Ancho = value;

base.Alto = value;

}

}

public override int Alto

{

get

{

return base.Alto;

}

set

{

base.Ancho = value;

base.Alto = value;

}

}

}

public class Rectangulo

{

public virtual int Ancho { get; set; }

public virtual int Alto { get; set; }

}

Principio de Substitución de Liskov[Test]

public void AreaRectangulo()

{

Rectangulo r =

new Cuadrado

{

Ancho = 5,

Alto = 2

};

// Fallará pues cuadrado establece

// a 2 el ancho y el alto

Assert.IsEqual(r.Ancho*r.Alto, 10); // false

}

Patrón Software

Diseño por Contratos

[Test]

public void AreaRectangulo()

{

Rectangulo r = new Cuadrado {Ancho = 5, Alto = 2};

// Fallará pues cuadrado establece

// a 2 el ancho y el alto

Assert.IsEqual(r.Ancho*r.Alto, 10); // false

}

Principio Inyección Dependencias

Principio Inyección Dependencias

public class EstacioMeteorologica

{

public void MostrarDatos()

{

Barometro barometro = new Barometro();

Termometro termometro = new Termometro();

int presion = barometro.Valor;

int temperatura = termometro.Valor;

Console.WriteLine(

string.Format("Datos a {0} \nTemperatura: {1}\nPresión:{2}",DateTime.Now, temperatura, presion));

}

}

Principio Inyección Dependencias

•Las clases de alto nivel no deberían depender sobre las clases de bajo nivel. Ambas deberían

depender de las abstracciones.•Las abstracciones deberían no depender de los detalles. Los detalles deberían depender de las abstracciones.

Robert C. Martin

Principio Inyección Dependencias

Principio Inyección Dependencias

public class EstacioMeteorologica

{

private IMeteoReferencia __dispo;

public EstacioMeteorologica(

IMeteoReferencia dispositivo)

{

_ __dispo = dispositivo;

}

public void MostrarDatos()

{

Console.WriteLine(

string.Format("Fecha/Hora {0}", DateTime.Now));

Console.WriteLine(_ __dispo());

}

}

Inversión Del Control (IoC)

Patrón Software

Principio Segregación Interfaces

Principio Segregación Interfacesclass Modelo2002 : ImpresoraMultifuncional {

public override void Imprimir()

{

Impresion.EnviarImpresion();

}

public override void Escanear()

{

Escaner.DigitalizarAFormatoPng();

}

public override void Cancelar()

{

Impresion.CancelarImpresion();

}

public override void EnviarFax()

{

throw new System.NotImplementedException();

}

public void EnviarEMail() {

//enviamos por correo electrónico}

}

Principio Segregación Interfaces

Los clientes no deben ser forzosamente dependientes de las interfaces que no utilizan.

Robert C. Martin

Principio Segregación Interfacespublic interface IImprimible

{

void Imprimir();

}

public interface IFotocopiable

{

void Fotocopiar();

}

public interface IEscaneable

{

void Escanear();

}

public interface IFaxCompatible

{

void EnviarFax();

void RecibirFax();

}

public interface ITcpIpCompatible

{

void EnviarEMail();

}

class Modelo1998 : IImprimible, IEscaneable, IFaxCompatible

{... }class Modelo2000 : IImprimible, IEscaneable, IFaxCompatible, IFotocopiable

{...}

class Modelo2002 : IImprimible, IEscaneable, IFotocopiable, ITcpIpCompatible

{...}

Patrón Software

Principios OO

• Encapsular aquellas partes susceptibles devariaciones

• Más composición, menos herencia

• Programa interfaces, no implementaciones

• Aboga por el bajo acoplamiento

• Ábrete a extensiones, ciérrate a modificaciones.

• Depende de abstracciones, no de clases concretas

• Sólo habla a “tus amigos”.

• “No nos llames; nosotros lo haremos”

• Una clase debe tener una única razón de cambio.

• Analiza el tamaño de los métodos. Los if/switch noshablan.

Blog: http://josemigueltorres.net

Twitter: @alegrebandolero

Email: josemiguel.torres@mrw.es