Inicio » Comunidad » Switch Code Smell

Switch Code Smell

1
0

Un switch puede ser visto como un code smell si las operaciones que realiza son bastantes complejas y si, por lo general, se suele modificar bastante añadiendo o quitando operaciones. El switch de tipo factoría no es tratado como code smells.

Por ejemplo, el siguiente código nos permite calcular el precio de un producto en función de su tipo.

public enum ProductType
{
    Car,
    Computer,
    Sport
}

public class Product {
    private ProductType type;
    private int price;

    public Product(ProductType type, int price) {
        this.type = type;
        this.price = price;
    }

    public int Calculate() {
        switch (this.type) {
            case ProductType.Car:
                return this.price * 100;
            case ProductType.Computer:
                return this.price * 200;
            case ProductType.Sport:
                return this.price * 1000;
            default:
                throw new System.Exception("Incorrect Product Type");
        }
    }
}

Aparentemente todo esta bien hasta que viene negocio y nos pide añadir un tipo de producto «bikes» y la operación «price * 50» para poder calcular su precio. Simple, no? tan solo tenemos que añadir otro enum para ProductType, añadir otra condición en el switch y añadir su operación dentro. El problema con este enfoque es que se está violando el principio Open/Close de SOLID, ya que no esta abierto a la extensión.

Vamos a refactorizar el código:

public class Product {
    private ProductType type;
    private int price;
    private PriceCalculatorFactory priceCalculatorFactory;

    public Product(ProductType type, int price, PriceCalculatorFactory priceCalculatorFactory) {
        this.type = type;
        this.price = price;
        this.priceCalculatorFactory = priceCalculatorFactory;
    }

    public int Calculate() {
        IPriceCalculator priceCalculator = this.priceCalculatorFactory.Create(this.type);
        return priceCalculator.Calculate(this.price);
    }
}

public interface IPriceCalculator {
    int Calculate(int price);
}

public class CarPriceCalculator : IPriceCalculator {
    public int Calculate(int price)
    {
        return price * 100;
    }
}

public class ComputerPriceCalculator : IPriceCalculator {
    public int Calculate(int price)
    {
        return price * 200;
    }
}

public class SportPriceCalculator : IPriceCalculator {
    public int Calculate(int price)
    {
        return price * 1000;
    }
}

public class PriceCalculatorFactory {
    public IPriceCalculator Create(ProductType type) {
        IPriceCalculator priceCalculator = null;
        
        switch (type) {
            case ProductType.Car:
                priceCalculator = new CarPriceCalculator();
                break;
            case ProductType.Computer:
                priceCalculator = new ComputerPriceCalculator();
                break;
            case ProductType.Sport:
                priceCalculator = new SportPriceCalculator();
                break;
            default:
                throw new System.Exception("Invalid price calculator type");
        }

        return priceCalculator;
    }
}

Lo que hemos hecho aquí es utilizar el patrón estrategia para encapsular cada una de las operaciones de los tipos de producto y luego utilizar el patrón factoría que se encargará de crear la estrategia necesaria en función del tipo de producto para luego poder calcular la operación. De esta manera, ahora sí estamos abierto a la extensión (principio open/close) ya que si viene negocio y nos pide añadir otra operación más, ahora no tenemos que modificar la clase producto, sino tenemos que añadir una estrategia nueva y añadirla a la factoría.

Ahora bien, seguro que te estarás preguntando si compensa crear toda esta estructura compleja para unas operaciones tan sencillas. La respuesta es no, como bien dije antes, solo se debería hacer si son operaciones complejas y tienen cambios constantes.

0 resultados
Tu respuesta

Por favor, primero debes para enviar.

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad