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.