Follow treslines by email clicking Here!

Wednesday, August 20, 2014

Programming Design Pattern - Abstract Factory Pattern Applied - Best Practise

Hi there!

Today i'm gonna show the Abstract Factory design pattern in action. The Abstract Factory design pattern is a very useful programming design pattern while dealing with creation of default, complex product families.

I'm assuming here you already know the concepts and i'll be focusing on practise. The example i will provide is a nice way to show it how it could looks like. You can always come back here, take it, adapt it and use it in your applictions as you may need. So be sure you bookmark it or join the group here on the right side of this post subscribing it.

First of all, let's take a look at the UML diagram of it. After that we will take the analogy for our example.

The UML Diagram of the Abstract Factory Pattern


Pay close attention, because once you understand that, everything will become clear and simple to understand. That's the reason I'm putting always the UML first. That way you'll get an eye for it with the time.




The example

In this example we will build on the last post (Factory) and create coffee shops. Let's imagine that our coffee shop is growing up. We wanna create branches of our company. Imagine that our business is expanding and we are opening branches in other countries. That's what we will see here.

The Abstract Factory

Make sure you have done the example from the factory (see Factory), because we are building up on it. We use the same generic interface, but we pass now a CoffeeFactory to it. Pay close attention how simple and how clean it is! I love this concept.

import java.math.BigDecimal;

/**
 * abstract coffee shop factory
 * @author Ricardo Ferreira
 * @version 1.0
 * @since 08/04/2014
 */
public enum CoffeeShopFactory implements Factory < Coffee, CoffeeFactory > {
    STARBUCKS_BRASIL, STARBUCKS_ASIA, STARBUCKS_USA, STARBUCKS_EUROPE;
    @Override
    public Coffee create(CoffeeFactory... arg) {
        Coffee coffee = validate(arg);
        switch (this) {
        case STARBUCKS_ASIA:
            return createAsiaStarbuckCoffee(coffee);
        case STARBUCKS_BRASIL:
            return createBrasilStarbuckCoffee(coffee);
        case STARBUCKS_USA:
            return createUSAStarbuckCoffee(coffee);
        case STARBUCKS_EUROPE:
            return createEuropeStarbuckCoffee(coffee);
        default:
            return new LatteMachiatto(new BigDecimal("6.0"));
        }
    }

    private Coffee validate(CoffeeFactory[] arg) {
        if(!(arg.length > 0)){
            throw new IllegalArgumentException("CoffeeShopFactory needs a CoffeeFactory type");
        }
        return arg[0].create();
    }
    private Coffee createAsiaStarbuckCoffee(Coffee coffee) {
        coffee.addIngredient("no zugar", new BigDecimal("-1.0"));
        coffee.addIngredient("marger milk", new BigDecimal("4.0"));
        coffee.addIngredient("caramel", new BigDecimal("2.0"));
        return coffee;
    }
    private Coffee createBrasilStarbuckCoffee(Coffee coffee) {
        coffee.addIngredient("extra zugar", new BigDecimal("2.0"));
        coffee.addIngredient("no milk", new BigDecimal("-4.0"));
        coffee.addIngredient("choco", new BigDecimal("3.0"));
        return coffee;
    }
    private Coffee createUSAStarbuckCoffee(Coffee coffee) {
        coffee.addIngredient("sweetener", new BigDecimal("5.0"));
        coffee.addIngredient("soja milk", new BigDecimal("7.0"));
        coffee.addIngredient("no caramel", new BigDecimal("-2.0"));
        return coffee;
    }
    private Coffee createEuropeStarbuckCoffee(Coffee coffee) {
        coffee.addIngredient("no zugar", new BigDecimal("-1.0"));
        coffee.addIngredient("normal milk", new BigDecimal("2.5"));
        coffee.addIngredient("chantilly", new BigDecimal("4.5"));
        return coffee;
    }
}

Testing it

Finally, we can see the Abstract Factory in action. I love this concept. It makes things readable, simple and reusable.

public class Client {
    public static void main(String[] args) {
        // create coffe without args
        final Coffee simpleLatteMachiato = CoffeeFactory.LATTE_MACHIATTO.create();
        simpleLatteMachiato.addIngredient("choco", new BigDecimal("0.3"));
        simpleLatteMachiato.addIngredient("zugar", new BigDecimal("0.4"));
        simpleLatteMachiato.addIngredient("chantilly", new BigDecimal("0.6"));
        simpleLatteMachiato.removeIngredient("choco");
        System.out.println("Latte Machiatto: "+simpleLatteMachiato.getTotalPrice());
        // Create coffee using args
        final Coffee simpleExpresso = CoffeeFactory.EXPRESSO.create(new BigDecimal("4.0"));
        simpleExpresso.addIngredient("choco", new BigDecimal("0.3"));
        simpleExpresso.addIngredient("zugar", new BigDecimal("0.2"));
        simpleExpresso.addIngredient("chantilly", new BigDecimal("1.2"));
        System.out.println("Expresso: "+simpleExpresso.getTotalPrice());
        
        Coffee coffee;
        coffee = CoffeeShopFactory.STARBUCKS_EUROPE.create(CoffeeFactory.CAPUCCINO);
        System.out.println("STARBUCKS_EUROPE CAPPUCCINO: "+coffee.getTotalPrice());
        
        coffee = CoffeeShopFactory.STARBUCKS_BRASIL.create(CoffeeFactory.CAPUCCINO);
        System.out.println("STARBUCKS_BRASIL CAPPUCCINO: "+coffee.getTotalPrice());
        
        coffee = CoffeeShopFactory.STARBUCKS_USA.create(CoffeeFactory.CAPUCCINO);
        System.out.println("STARBUCKS_USA CAPPUCCINO: "+coffee.getTotalPrice());
        
        coffee = CoffeeShopFactory.STARBUCKS_ASIA.create(CoffeeFactory.CAPUCCINO);
        System.out.println("STARBUCKS_ASIA CAPPUCCINO: "+coffee.getTotalPrice());
    }
}

That's all! Hope you like it.

No comments:

Post a Comment