Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Principios SOLID

Principios SOLID

Avatar for Jorge Sánchez Fernández

Jorge Sánchez Fernández

October 21, 2015

Other Decks in Programming

Transcript

  1. ¿SOLID? • Acrónimo introducido por Robert C. Martin (Uncle Bob)

    a principios de la década 2000 • Haciendo nuestro código SOLID conseguimos un código flexible y escalable • Representa los 5 principios básicos de la programación orientada a objetos ◦ Single responsibility ◦ Open-closed ◦ Liskov substitution ◦ Interface segregation ◦ Dependency inversion
  2. • Cada clase debe tener solo una responsabilidad • Una

    responsabilidad es igual a un único motivo para cambiar • Si una clase tiene múltiples responsabilidades hay riesgo de modificar una responsabilidad pero alterar otra al estar ambas en el mismo sitio. • Hay que evitar clases muy grandes que hacen muchas cosas • Este principio aplica también a los métodos y funciones • Si aplicamos este principio estamos evitando duplicar código
  3. public ProductDto GetById(int id) { _logger.Debug(string.Format("Retrieving Product by Id:{0}", id));

    Product product = Context.Products.Where(p => p.ProductId == id); ProductDto Product = MapProductToProductDto(product); if (product == null) { throw new Exception("Product not found"); _logger.Debug(string.Format("ProductId:{0} not found", id)); } else { _logger.Debug(string.Format("Filling cache for product id:{0}", id)); System.Web.HttpContext.Current.Cache.Insert("Product_" + id, product, null, Cache.NoAbsoluteExpiration, TimeSpan.FromHours(24)); _logger.Debug(string.Format("Filled cache for product id:{0}", id)); } _logger.Debug(string.Format("Retrieved Product by Id:{0}", id)); return product; } ¿Responsabilidades?
  4. public ProductDto GetById(int id) { _logger.Debug(string.Format("Retrieving Product by Id:{0}", id));

    Product product = Context.Products.Where(p => p.ProductId == id); ProductDto Product = MapProductToProductDto(product); if (product == null) { throw new Exception("Product not found"); _logger.Debug(string.Format("ProductId:{0} not found", id)); } else { _logger.Debug(string.Format("Filling cache for product id:{0}", id)); System.Web.HttpContext.Current.Cache.Insert("Product_" + id, product, null, Cache.NoAbsoluteExpiration, TimeSpan.FromHours(24)); _logger.Debug(string.Format("Filled cache for product id:{0}", id)); } _logger.Debug(string.Format("Retrieved Product by Id:{0}", id)); return product; } Logging ¿Responsabilidades?
  5. public ProductDto GetById(int id) { _logger.Debug(string.Format("Retrieving Product by Id:{0}", id));

    Product product = Context.Products.Where(p => p.ProductId == id); ProductDto Product = MapProductToProductDto(product); if (product == null) { throw new Exception("Product not found"); _logger.Debug(string.Format("ProductId:{0} not found", id)); } else { _logger.Debug(string.Format("Filling cache for product id:{0}", id)); System.Web.HttpContext.Current.Cache.Insert("Product_" + id, product, null, Cache.NoAbsoluteExpiration, TimeSpan.FromHours(24)); _logger.Debug(string.Format("Filled cache for product id:{0}", id)); } _logger.Debug(string.Format("Retrieved Product by Id:{0}", id)); return product; } Logging Persistencia ¿Responsabilidades?
  6. public ProductDto GetById(int id) { _logger.Debug(string.Format("Retrieving Product by Id:{0}", id));

    Product product = Context.Products.Where(p => p.ProductId == id); ProductDto Product = MapProductToProductDto(product); if (product == null) { throw new Exception("Product not found"); _logger.Debug(string.Format("ProductId:{0} not found", id)); } else { _logger.Debug(string.Format("Filling cache for product id:{0}", id)); System.Web.HttpContext.Current.Cache.Insert("Product_" + id, product, null, Cache.NoAbsoluteExpiration, TimeSpan.FromHours(24)); _logger.Debug(string.Format("Filled cache for product id:{0}", id)); } _logger.Debug(string.Format("Retrieved Product by Id:{0}", id)); return product; } Logging Persistencia Mapeo ¿Responsabilidades?
  7. public ProductDto GetById(int id) { _logger.Debug(string.Format("Retrieving Product by Id:{0}", id));

    Product product = Context.Products.Where(p => p.ProductId == id); ProductDto Product = MapProductToProductDto(product); if (product == null) { throw new Exception("Product not found"); _logger.Debug(string.Format("ProductId:{0} not found", id)); } else { _logger.Debug(string.Format("Filling cache for product id:{0}", id)); System.Web.HttpContext.Current.Cache.Insert("Product_" + id, product, null, Cache.NoAbsoluteExpiration, TimeSpan.FromHours(24)); _logger.Debug(string.Format("Filled cache for product id:{0}", id)); } _logger.Debug(string.Format("Retrieved Product by Id:{0}", id)); return product; } Logging Persistencia Cache Mapeo ¿Responsabilidades?
  8. public ProductDto GetById(int id) { _logger.Debug(string.Format("Retrieving Product by Id:{0}", id));

    Product product = Context.Products.Where(p => p.ProductId == id); ProductDto Product = MapProductToProductDto(product); if (product == null) { throw new Exception("Product not found"); _logger.Debug(string.Format("ProductId:{0} not found", id)); } else { _logger.Debug(string.Format("Filling cache for product id:{0}", id)); System.Web.HttpContext.Current.Cache.Insert("Product_" + id, product, null, Cache.NoAbsoluteExpiration, TimeSpan.FromHours(24)); _logger.Debug(string.Format("Filled cache for product id:{0}", id)); } _logger.Debug(string.Format("Retrieved Product by Id:{0}", id)); return product; } Logging Persistencia Cache Mapeo Orquestación (dirigir orden) ¿Responsabilidades?
  9. public ProductDto GetById(int id) { this.ProductLogger.Reading(id); Product product = this.Repository.GetById(id);

    ProductDto Product = this.productMapper.MapToDto(product); if (product == null) { throw new Exception("Product not found"); this.ProductLogger.NotFound(id); } else { this.ProductLogger.FillingCache(id); this.cache.Insert("Product_" + id, product); this.ProductLogger.FilledCache(id); } this.ProductLogger.Readed(id); return product; } Orquestación (dirigir orden) ¿Responsabilidades?
  10. public class ProductLogger { ... public void Reading ( int

    id) { _logger.Debug( string.Format("Reading Product by Id:{0}" , id)); } public void Readed(int id) { _logger.Debug( string.Format("Readed Product by Id:{0}" , id)); } public void NotFound( int id) { _logger.Debug( string.Format("ProductId:{0} not found" , id)); } ... } public class ProductService { ... public ProductDto GetById(int id) { ... } } public class Cache { ... public void Add(string key, object obj) { System.Web. HttpContext .Current.Cache.Insert( "Product_" + id, product, null, Cache.NoAbsoluteExpiration, TimeSpan.FromHours(24)); } ... } public class ProductMapper { ... public ProductDto MapToDto(Product product) { ... } ... } Orquestación (dirigir orden) public class ProductRepository { ... public Product GetById(int id) { ... } ... } Logging Persistencia Mapeo Cache
  11. • Patrones como Composite, Strategy, Decorator, Factory y Observer ayudan

    a cumplir este principio • Bertrand Meyer fue el primero que habló sobre este principio en 1988 en el libro Object-Oriented Software Construction. • Las entidades de software deben estar abiertas para su extensión, pero cerradas para su modificación. • Deberían poder extender o modificar su comportamiento sin modificarse • Abrir una clase para editarla conlleva riesgos de afectar a más cosas
  12. Para ponerse un abrigo no hace falta abrir el tórax

    Para ponerse un sombrero no hace falta abrir el cerebro
  13. Requiere modificar la clase static void Main(string[] args) { if

    (string.Equals(args[0], UPDATE_CATALOGPRODUCT_TO_CA)) { //Synchronizing from catalog to CA ... } if (string.Equals(args[0], UPDATE_CA_TO_INVENTORYPRODUCT)) { //Synchronizing from CA to Catalog ... } if (string.Equals(args[0], ASSIGN_ALLLABELS_CA)) { //Assigning labels to CA ... } } ¿Añadir más casos de sync? Aplicaciones de consola
  14. public interface ISynchronizer { string Key { get; } void

    Execute(); } public class dTLPToCASynchronizer : ISynchronizer { public string Key { get {return "-dtlptoca" ;} } public void Execute() { ... } } public class CATodTLPSynchronizer : ISynchronizer { public string Key { get {return "-catodtlp" ;} } public void Execute() { ... } } public class SyncronizerFactory { static List<ISynchronizer > synchronizers = null; static SyncronizerFactory() { var types = Assembly .GetExecutingAssembly() . GetTypes().Where(mytype => mytype.GetInterfaces().Contains( typeof(ISynchronizer ))); synchronizers = new List<ISynchronizer >(); foreach (Type type in types) { synchronizers.Add( Activator .CreateInstance(type)); } } public static ISynchronizer GetSyncronizer( string key) { ISynchronizer synchzer = synchronizers.FirstOrDefault(); if (synchronizer == null) throw new Exception ("Synchronizer not found” ); return synchronizer; } } class Program { static void Main(string[] args) { ISynchronizer synchronizer = SyncronizerFactory .GetSyncronizer(args[0]); synchronizer.Execute(); } }
  15. • Para conseguir que sean intercambiables: ◦ Las clases derivadas

    no pueden modificar las capacidades de su clase base. ◦ Dos clases que heredan de otra tienen que tener las mismas capacidades. ◦ Dos clases que implementan el mismo interface tienen que tener las mismas capacidades. • Acuñado por Barbara Liskov en el año 1987 durante una conferencia sobre Jerarquía y Abstracción de datos. • Clases compartiendo abstracción deben poder ser intercambiables.
  16. Parece un pato, suena como un pato, pero el de

    goma, necesita pilas y no come. No puedo sustituir uno por otro, la abstracción no es correcta
  17. Ej 1: Clásico ejemplo de Herencia (No he encontrado este

    caso en dTLP) public 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 { private int ancho; private int alto; public virtual int Ancho { get { return ancho; } set { ancho = value; } } public virtual int Alto { get { return alto; } set { alto = value; } } } [TestMethod] public void AreaRectangulo() { Rectangulo r = new Rectangulo { Ancho = 5, Alto = 2 }; // el test pasa Assert.AreEqual(r.Ancho * r.Alto, 10); // true } [TestMethod] public void AreaRectangulo() { Rectangulo r = new Cuadrado{ Ancho = 5, Alto = 2 }; // Fallará, pues Cuadrado establece // a 2 el ancho y el alto Assert.AreEqual(r.Ancho * r.Alto, 10); // false }
  18. public interface IMultichannelCASellerService { ICAResult SyncProductsComplete (IEnumerable<ProductInfoCA> data); List<ProductInfoCA> GetFilteredInventoryItemList

    (int pageNumber, int pageSize, string prefixSKU); } Ej 2: Interface public class MultichannelCASellerService : IMultichannelCASellerService { public ICAResult SyncProductsComplete (IEnumerable<ProductInfoCA> data) { //code } public List<ProductInfoCA> GetFilteredInventoryItemList (string prefixSKU) { //code } } public class MultichannelCASellerFTPService : IMultichannelCASellerService { public ICAResult SyncProductsComplete (IEnumerable<ProductInfoCA> data) { //code } public List<ProductInfoCA> GetFilteredInventoryItemList (string prefixSKU) { throw new NotImplementedException(); } } El uso de NotSupportException o NotImplementedException viola este principio
  19. • Este principio divide las interfaces que son muy grandes

    en otras más pequeñas y más específicas para que los clientes sólo tendrán que saber sobre el métodos que son de interés para ello • Fue propuesto originalmente por Robert C. Martin (Uncle Bob). • Ayuda a resolver la violación del principio de sustitución de Liskov por interface. • Es un ejemplo de cómo los principios SOLID interactúan y mejoran entre sí. • Este principio establece que ningún cliente debe ser forzado a depender de métodos que no utiliza. • Las interfaces pesadas no permiten escalar bien.
  20. public interface IMultichannelCASellerWriteService { ICAResult SyncProductsComplete (IEnumerable<ProductInfoCA> data); } public

    class MultichannelCASellerService : IMultichannelCASellerReadService, IMultichannelCASellerWriteService { public ICAResult SyncProductsComplete (IEnumerable<ProductInfoCA> data) { //code } public List<ProductInfoCA> GetFilteredInventoryItemList (string prefixSKU) { //code } } public class MultichannelCASellerFTPService : IMultichannelCASellerWriteService { public ICAResult SyncProductsComplete (IEnumerable<ProductInfoCA> data) { //code } } public interface IMultichannelCASellerReadService { List<ProductInfoCA> GetFilteredInventoryItemList (int pageNumber, int pageSize, string prefixSKU); } Solucionando NotSupportException o NotImplementedException
  21. • Fue propuesto originalmente por Robert C. Martin (Uncle Bob).

    • Los módulos de alto nivel no deberían depender de los de bajo nivel, ambos deberían depender de abstracciones. • Las abstracciones no deben depender de los detalles, los detalles deben depender de las abstracciones. • La ventana de aplicar este principio de nuevo poder escalar mejor modificando el menor código posible. • Importante, la abstracción la marca el cliente • Este principio ayuda a poder realizar test unitarios • Voy a poder probar una clase y simular sus simular sus dependencias
  22. ¿Soldamos directamente una lámpara al cableado eléctrico de un pared?

    No, creamos abstracción enchufe Asi podemos enchufar cualquier aparato electrónico
  23. internal class AmazonManager { ... public AmazonManager(ILogger amazonProductLogger) { this.amazonProductLogger

    = amazonProductLogger; _amazonAgent = new ProductAdvertisingAPIClient(...); } ... } public interface IProductAdvertisingAPIClient { } public class SOAPProductAdvertisingAPIClient: IProductAdvertisingAPIClient { } public class RESTProductAdvertisingAPIClient: IProductAdvertisingAPIClient { } internal class AmazonManager { ... public AmazonManager(ILogger amazonProductLogger, IProductAdvertisingAPIClient amazonAgent) { this.amazonProductLogger = amazonProductLogger; this.amazonAgent = amazonAgent; } ... }
  24. Cursos y videos de pago • http://www.pluralsight.com/courses/encapsulation-solid • http://www.pluralsight.com/courses/principles-oo-design •

    http://code.tutsplus.com/courses/solid-design-patterns-in-c • https://cleancoders.com/category/clean-code