Ad

Replace Conditional With Polymorphism

- 1 answer

I am trying to understand this clean code practice with an example. Consider a class Product having switch case for discount. I am trying to replace switch statement with polymorphism.

Before code:

class Product {
    String priceCode;
    int discount;

    Product(String priceCode) {
        setDiscount(priceCode);
    }

    public int getDiscount() {
        return discount;
    }

    public void setDiscount(String priceCode) {
        switch (priceCode) {
            case "CODE1":
                discount = // some logic;
            case "CODE2":
                discount = // some other logic;
            case "CODE3":
                discount = // some other logic;
        }
    }
}

In below code as you can see I removed switch statement but I still have if conditions to create an object of discountStrategy. My question is I still have if conditions which I am trying to remove with Polymorphism.

After code:

class Product {
    String priceCode;
    DiscountStrategy discountStrategy;

    Product(String priceCode) {
        setDiscount(priceCode);
    }

    public int getDiscount() {
        return discountStrategy.getDiscount();
    }

    public void setDiscount(String priceCode) {
        if (priceCode.equals("CODE1")) {
            discountStrategy = new DiscountStrategy1();
        } else if (priceCode.equals("CODE2")) {
            discountStrategy = new DiscountStrategy2();
        }
        // ...
    }
}

interface DiscountStrategy {
    public int getDiscount();
}

class DiscountStrategy1 implements DiscountStrategy {
    public int getDiscount() {
        // calculate & return discount;
    }
}

class DiscountStrategy2 implements DiscountStrategy {
    public int getDiscount() {
        // calculate & return discount;
    }
}

class DiscountStrategy3 implements DiscountStrategy {
    public int getDiscount() {
        // calculate & return discount;
    }
}

Can you please help me understand this concept with better implementation of this example?

Ad

Answer

I think that Product class must not be aware about the discount creation process, it should only use a discount. So, my suggestion is to create a discount factory with a Map that will hold different discount implementations:

class DiscountFactory {
    private static final Map<String, DiscountStrategy> strategies = new HashMap<>();
    private static final DiscountStrategy DEFAULT_STRATEGY = () -> 0;

    static {
        strategies.put("code1", () -> 10);
        strategies.put("code2", () -> 20);
    }

    public DiscountStrategy getDiscountStrategy(String priceCode) {
        if (!strategies.containsKey(priceCode)) {
            return DEFAULT_STRATEGY;
        }
        return strategies.get(priceCode);
    }
}

After that, the Product class can be simplified:

class Product {
    private DiscountStrategy discountStrategy;

    Product(DiscountStrategy discountStrategy) {
        this.discountStrategy = discountStrategy;
    }

    public int getDiscount() {
        return discountStrategy.getDiscount();
    }
}

Functional interface will allow you to create different implementations using lambda expressions:

interface DiscountStrategy {
    int getDiscount();
}

And finally, example of the use of a product together with discount:

DiscountFactory factory = new DiscountFactory();
Product product = new Product(factory.getDiscountStrategy("code1"));
Ad
source: stackoverflow.com
Ad