Showing posts with label Factory. Show all posts
Showing posts with label Factory. Show all posts

Wednesday, August 20, 2014

Programming Design Pattern - Factory Pattern Applied - Best Practise

Hi there!

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

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 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 our example we will see, how we could implement a coffeshop like starbucks. We may think that's a complicated think, but in fact it is not. With the right design it can be very simple. Imagine you are grounding your coffee company. You want to offer lots of different coffee types. How could we do it? In this example we will see it.

The Product

Normally we will start by the products we have. That's a typical characteristic and keyword for the simple factory. All concrete coffee types will extend from it.

// DEFINE COMMON PRODUCT INTERFACE
public abstract class Coffee {
    private BigDecimal basePrice= BigDecimal.ZERO;
    private HashMap < String, BigDecimal > addOns;
    public Coffee(BigDecimal basePrice){
        addOns =  new HashMap < String, BigDecimal > ( );
        this.basePrice=basePrice;
    }
    public BigDecimal  getTotalPrice(){return this.basePrice;}
    public void addIngredient(String name, BigDecimal price){
        this.basePrice=this.basePrice.add(price);
        addOns.put(name, price);
    }
    public void removeIngredient(String name){
        final BigDecimal price = addOns.get(name);
        this.basePrice=this.basePrice.subtract(price);
        addOns.remove(name);
    }
}

The Coffee types (products)

Here we implement all coffees we intend to offer.

import java.math.BigDecimal;

public class Cappuccino extends Coffee {
    public Cappuccino(BigDecimal basePrice) {
        super(basePrice);
    }
}
public class LatteMachiatto extends Coffee {
    public LatteMachiatto(BigDecimal basePrice) {
        super(basePrice);
    }
}
public class Intenso extends Coffee {
    public Intenso(BigDecimal basePrice) {
        super(basePrice);
    }
}
public class Expresso extends Coffee {
    public Expresso(BigDecimal basePrice) {
        super(basePrice);
    }
}

The factory's common interface

Here we define the contract from the factory. Every factory implements it.

/**
 * Common interface to be used while creating simple factories.
 * @param P product to be created from this factory. The interface from the product.
 * @param A argument: an optional creation attribute. You may leave it empty.
 * @author Ricardo Ferreira
 * @version 1.0
 * @since 08/04/2014
 */
public interface Factory < P , A > {
   /**
    * creates a default product without argument or a specific product if you pass any arguments
    * @param argument an optional creation attribute
    * @return a default concrete product
    */
    P create(@SuppressWarnings("unchecked") A... arg);
}

The Factory itself

A new state of the art is to use enum's to create factories. Why? Because it is easier, cleaner and can be self-referenced as we will see.

/**
 * Simple coffee factory
 * @author Ricardo Ferreira
 * @version 1.0
 * @since 08/04/2014
 */
public enum CoffeeFactory implements Factory < Coffee, BigDecimal > {
    CAPUCCINO, LATTE_MACHIATTO, EXPRESSO, INTENSO;
    @Override
    public Coffee create(BigDecimal... arg) {
        boolean hasArg = arg.length > 0;
        switch (this) {
        case LATTE_MACHIATTO:
            return hasArg?new LatteMachiatto(arg[0]):new LatteMachiatto(new BigDecimal("2.0"));
        case CAPUCCINO:
            return hasArg?new Cappuccino(arg[0]):new Cappuccino(new BigDecimal("3.0"));
        case EXPRESSO:
            return hasArg?new Expresso(arg[0]):new Expresso(new BigDecimal("4.0"));
        case INTENSO:
            return hasArg?new Intenso(arg[0]):new Intenso(new BigDecimal("5.0"));
        default:
            return new LatteMachiatto(new BigDecimal("6.0"));
        }
    }
}

The Test

Finally, we can see how our new coffee shop factory would looks like.

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());
    }
}

That's all! Hope you like it!

😱👇 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘‡

Be sure to read, it will change your life!
Show your work by Austin Kleonhttps://amzn.to/34NVmwx

This book is a must read - it will put you in another level! (Expert)
Agile Software Development, Principles, Patterns, and Practiceshttps://amzn.to/30WQSm2

Write cleaner code and stand out!
Clean Code - A Handbook of Agile Software Craftsmanship: https://amzn.to/33RvaSv

This book is very practical, straightforward and to the point! Worth every penny!
Kotlin for Android App Development (Developer's Library): https://amzn.to/33VZ6gp

Needless to say, these are top right?
Apple AirPods Pro: https://amzn.to/2GOICxy

😱👆 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘†

Saturday, October 13, 2012

Understanding Dependency Inversion in real life


Hi there! Today i wanna share a real life example of dependency Inversion with you. In my RCP-Client developer career we had often the challange that due some customer change requests, we were forced to instantiate some domain specific dialogs from base. The problem here is that base (package: com.yourcompany.base) is not allowed to create dependencies to domain specific packages. So how could we solve this problem? We must inverse the dependency. What do we need? We will create a dependency registry in which we register domain specific dialog factories to be able to instantiate them from the base without having to create dependencies from base to specific domain packages.

The common factory interface

We define a factory interface in base. Let's say package is called: com.yourCompany.base.



interface DialogFactory{
    Dialog createFilterDialog();
}

In the same package we define an interface for the depencency inversion of our registry later:

// then we define also in base the interface for DependencyInversion in general. 
// to be used by all Registries we need in future. package: com.yourCompany.base
public interface DependencyInversion<T> {

    void registerFactory(String factoryMapKey, T factory);

    void unregisterFactory(String factoryMapKey);

    T getRegisteredFactoryOrNull(String factoryMapKey);
}

Now we need a Dependency Inversion Helper, which will handle the factory map later:


import java.util.HashMap;
import java.util.Map;

// for the same general reason, we define a dependency inversion helper which
// handle with the factoryMaps for any kind of factory in future. This class is
// also placed in base package: com.yourCompany.base
public class DependencyInversionHelper<T> {

    private Map<String, T> factoryMap = new HashMap<String, T>();

    public void unregisterIfExistsInMap(String factoryMapKey) {
        if (doesFactoryExistInMap(factoryMapKey)) {
            removeFactoryFromMap(factoryMapKey);
        }
    }

    public void registerIfNotExistsInMap(String factoryMapKey, T factory) {
        if (!doesFactoryExistInMap(factoryMapKey)) {
            insertFactoryIntoMap(factoryMapKey, factory);
        }
    }

    public boolean doesFactoryExistInMap(String factoryMapKey) {
        return this.factoryMap.containsKey(factoryMapKey);
    }

    public void insertFactoryIntoMap(String factoryMapKey, T factory) {
        this.factoryMap.put(factoryMapKey, factory);
    }

    public void removeFactoryFromMap(String factoryMapKey) {
        this.factoryMap.remove(factoryMapKey);
    }

    public T getRegisteredFactoryOrNull(String factoryMapKey) {
        return (T) (doesFactoryExistInMap(factoryMapKey) ? this.factoryMap.get(factoryMapKey) : null);
    }

}

The Registry

And finally we define in the same package our registry, which uses the helper and implements DependencyInversion:


// Now every thing we need to implement is the registry itself. This will be a singleton because
// we just need it once in the whole application. We place it also in base: com.yourCompany.base 
public class FilterDialogDependencyInversionRegistry implements DependencyInversion<DialogFactory> {

    private static FilterDialogDependencyInversionRegistry instance = new FilterDialogDependencyInversionRegistry();
    private DependencyInversionHelper<DialogFactory> helper = new DependencyInversionHelper<DialogFactory>();

    private FilterDialogDependencyInversionRegistry() {
        // singleton: we just need one global registry for it.
    }

    public static FilterDialogDependencyInversionRegistry instance() {
        return instance;
    }

    @Override
    public void registerFactory(String factoryMapKey, DialogFactory factory) {
        helper.registerIfNotExistsInMap(factoryMapKey, factory);
    }

    @Override
    public void unregisterFactory(String factoryMapKey) {
        helper.unregisterIfExistsInMap(factoryMapKey);
    }

    @Override
    public DialogFactory getRegisteredFactoryOrNull(String factoryMapKey) {
        return helper.getRegisteredFactoryOrNull(factoryMapKey);
    }

}

Ready for implementation:

Now we are able to register all factories we need with this registry. Because this registry is visible in base and in any other domain specific package, we can access our new Registry from anywhere and get the factory we need for any factoryMapKey we define. In Eclipse RCP this is usually done in the method  start() from the application. when the method getRegisteredFactoryOrNull(key) is called, we get a  DialogFactory and are able now to call the method createFilterDialog() from it. What it happens now is very cool. Any interface knows its implementation and creates the right dialog without having dependencies to the base modul. Any domain specific factory must only implement DialogFactory. That's all.

😱👇 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘‡

Be sure to read, it will change your life!
Show your work by Austin Kleonhttps://amzn.to/34NVmwx

This book is a must read - it will put you in another level! (Expert)
Agile Software Development, Principles, Patterns, and Practiceshttps://amzn.to/30WQSm2

Write cleaner code and stand out!
Clean Code - A Handbook of Agile Software Craftsmanship: https://amzn.to/33RvaSv

This book is very practical, straightforward and to the point! Worth every penny!
Kotlin for Android App Development (Developer's Library): https://amzn.to/33VZ6gp

Needless to say, these are top right?
Apple AirPods Pro: https://amzn.to/2GOICxy

😱👆 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘†