Showing posts with label builder pattern. Show all posts
Showing posts with label builder pattern. Show all posts

Friday, August 8, 2014

Programming Design Pattern - Builder Pattern Applied - Best Practise

Hi there!

Today i'm gonna share the first of a brand new programming design pattern series i made. The builder pattern is a very useful and common pattern while developing serious apps. In this post i'll give a tiny builder pattern framework, so you can always come back here and get it to work with.

A mnemonic, while dealing with builder pattern, is to think about customization. I always think about it, when i'm figuring out if i should use it or if i better take a factory. That's the way it works better for me. try yourself.

The UML Builder Pattern

Here is how the little framework looks like. Simple, nice and straightforward.


The code behind it

The code is also very simple, small, clean and self-explanatory. I like to code expressive, so i don't need to comment a lot. In this sample here i did, because it has a tutorial character. While developing i created some convention to my self. I think it is very important to do so. It is like applying the right grammar on a language while developing. 

For example: If i'm using the Builder Pattern, i always put the suffix Builder at the end. Well you may say or think now: what? But thats in fact a very, very, important info for beginners and expirienced developers. They will automatically see the idea behind it and will try not to break the pattern. In fact expirienced developers will love it and try to continue a good work, because they know, that the developer who wrote this, knows what he did and for sure there was a reason for it.

So always try to be clear enough and give the right information on the right places. Someone else will thank you later.  But now to the code... :)

// 1. EXAMPLE: PARTS OF THE CUSTOMIZABLE PRODUCT WE WANT
public interface Part {
    // DEFINE THE METHODS YOUR PARTS WILL HAVE...
    void anyMethodNameYouLike();
}

// 2. THE BUILDER METHOD WILL ADD 
// PARTS RETURNING THE BUILDER ITSELF
public interface BuildContract < B > {
    B mount(Part part);
}

// 3. DEFINE THE BUILDER'S CONTRUCTION METHOD
// WHICH BUILDS AND RETURNS THE FINAL PRODUCT "T"
public interface Builder < T > extends BuildContract < Builder < T > > {
    T build();
}

A real example

Nothing better then that to fix it and understand it better. Let´s implement a cake bakery. A colleague of yours wants to open a bakery and asked you to program a bakery's software for him. Let's do it.. :)
And by the way, I commend you heartily, using a UML diagram tool is as visualization mechanism to show your ideas and improve your design skills. Lets start by the UML:


The analogy

Let's now use our tiny framework and make the analogy for our bakery. Ingredient is the Part, Recipe is the BuilderContract and  Builder is the builder itself. Cake is the final, customizable product. CakeBuilder is the class which actually creates the product after customization (after the addition of as many parts - ingredients - as you want). The client would be the final client or your colleague taking the order. Just use or imagination... :) Let's dive into code now... 

The Ingredients (Parts)

The parts in our example are the ingredients. Let's implement some ingredients to use it later to make a cake. 
 
// 1. EXAMPLE: PART TO CUSTOMIZATE "INGREDIENTS"
public interface Ingredient {
    // INGREDIENTS WILL HAVE...
    void printName();
    String getUnitPrice();
    void printCalories();
}
public class LightMilk implements Ingredient {

    private int deciLiter;
    private int calories;
    private String unitPrice;
    
    public LightMilk(int deciLiter){this.deciLiter=deciLiter;}
    
    public LightMilk(int deciLiter, int calories, String unitPrice) {
        super();
        this.deciLiter = deciLiter;
        this.calories = calories;
        this.unitPrice = unitPrice;
    }

    @Override public void printName() {System.out.printf(" Light Milk");}
    @Override public String getUnitPrice() {return unitPrice;}
    @Override public void printCalories() {System.out.printf(" 76kc");}
    public int getDeciLiter() {return deciLiter;}
    public void setDeciLiter(int deciLiter) {this.deciLiter = deciLiter;}
    public int getCalories() {return calories;}
    public void setCalories(int calories) {this.calories = calories;}
    public void setUnitPrice(String unitPrice) {this.unitPrice = unitPrice;}
}
public class Sugar implements Ingredient {

    private int gram;
    private int calories;
    private String unitPrice;
    
    public Sugar(int deciLiter){this.gram=deciLiter;}
    
    public Sugar(int gram, int calories, String unitPrice) {
        super();
        this.gram = gram;
        this.calories = calories;
        this.unitPrice = unitPrice;
    }

    @Override public void printName() {System.out.printf(" Sugar");}
    @Override public String getUnitPrice() {return unitPrice;}
    @Override public void printCalories() {System.out.printf(" 40kc");}
    public int getGram() {return gram;}
    public void setGram(int gram) {this.gram = gram;}
    public int getCalories() {return calories;}
    public void setCalories(int calories) {this.calories = calories;}
    public void setUnitPrice(String unitPrice) {this.unitPrice = unitPrice;}
}
public class Choco implements Ingredient {
    private int gram;
    private int calories;
    private String unitPrice;
    public Choco(int gram, int calories, String unitPrice) {
        super();
        this.gram = gram;
        this.calories = calories;
        this.unitPrice = unitPrice;
    }
    public int getGram() {return gram;}
    public void setGram(int gram) {this.gram = gram;}
    public int getCalories() {return calories;}
    public void setCalories(int calories) {this.calories = calories;}
    public void setUnitPrice(String unitPrice) {this.unitPrice = unitPrice;}

    @Override public void printName() {System.out.printf(" Chocolate");}
    @Override public void printCalories() {System.out.printf(" 389kc");}
    @Override public String getUnitPrice() {return unitPrice;}
}
public class NoSugar implements Ingredient {

    private int gram;
    private int calories;
    private String unitPrice;
    
    public NoSugar(int deciLiter){this.gram=deciLiter;}
    
    public NoSugar(int gram, int calories, String unitPrice) {
        super();
        this.gram = gram;
        this.calories = calories;
        this.unitPrice = unitPrice;
    }

    @Override public void printName() {System.out.printf(" No Sugar");}
    @Override public String getUnitPrice() {return unitPrice;}
    @Override public void printCalories() {System.out.printf(" 0kc");}
    public int getGram() {return gram;}
    public void setGram(int gram) {this.gram = gram;}
    public int getCalories() {return calories;}
    public void setCalories(int calories) {this.calories = calories;}
    public void setUnitPrice(String unitPrice) {this.unitPrice = unitPrice;}
}
public class Milk implements Ingredient {

    private int deciLiter;
    private int calories;
    private String unitPrice;
    
    public Milk(int deciLiter){this.deciLiter=deciLiter;}
    
    public Milk(int deciLiter, int calories, String unitPrice) {
        super();
        this.deciLiter = deciLiter;
        this.calories = calories;
        this.unitPrice = unitPrice;
    }

    @Override public void printName() {System.out.printf(" Milk");}
    @Override public String getUnitPrice() {return unitPrice;}
    @Override public void printCalories() {System.out.printf(" 128kc");}
    public int getDeciLiter() {return deciLiter;}
    public void setDeciLiter(int deciLiter) {this.deciLiter = deciLiter;}
    public int getCalories() {return calories;}
    public void setCalories(int calories) {this.calories = calories;}
    public void setUnitPrice(String unitPrice) {this.unitPrice = unitPrice;}
}

The Builder's Contract

This is the Recipe in our example.

// 2. THE BUILDER METHOD WILL ADD 
// INGREDIENTS RETURNING THE BUILDER ITSELF
public interface Recipe < B > {
    B addIngredient(Ingredient ingredient);
}
// 3. DEFINE THE BUILDER CONTRUCTION METHOD
// WHICH BUILDS AND RETURNS THE FINAL PRODUCT "T"
public interface Builder < T > extends Recipe < Builder < T > > {
    T build();
}
import java.util.ArrayList;
import java.util.List;
// 4. IMPLEMENT THE BUILDER ACC. TO YOUR NEEDS
public class CakeBuilder implements Builder < Cake > {
    // IN THIS CASE THE PARTS ARE THE INGREDIENTS
    private List < Ingredient > ingredients=new ArrayList < Ingredient > ( );
    @Override
    public Cake build() {
        if(!ingredients.isEmpty()){
            // THE FINAL PRODUCT IS A CHOCO-MUFFIN
            return new Cake(ingredients);
        }
        return new Cake(null);
    }
    @Override
    // BECAUSE I ALWAYS GET A BUILDER BACK, I'M ABLE TO
    // ADD A LOT OF PARTS BEFORE I CALL "BUILD()"
    public Builder < Cake > addIngredient(Ingredient ingredient) {
        if(ingredient!=null){
            ingredients.add(ingredient);
        }
        return this;
    }
}

The product

In our example the product to build is a cake.
import java.util.List;

public class Cake {
    public Cake(List < Ingredient > ingredients){
        String muffin = "";
        if(ingredients==null){
            System.out.println(" zero cake "+muffin);
            return;
        }
        // PRINT OUT MUFFIN INGREDIENTS
        System.out.printf(" Cake with: ");
        for (Ingredient ingredient : ingredients) {
            ingredient.printName();
        }
        // PRINT OUT PART PRICES
        for (Ingredient ingredient : ingredients) {
            muffin+=" "+ingredient.getUnitPrice();//NOPMD
        }
        System.out.println(" - Price: "+muffin);
    }
    public void printResult(){
        System.out.println(" Cake is ready!");
    }
}

Testing it

Finally the client test. Here we can see the usage of it:
// 5. TESTING THE CHOCO-BUILDER
public class Client {
    public static void main(String[] args) {
        Builder < Cake > chocoMuffinBuilder = new CakeBuilder();
        chocoMuffinBuilder.addIngredient(new Choco(10, 23, "3.39"));
        chocoMuffinBuilder.addIngredient(new Milk(34, 67, "1.57"));
        chocoMuffinBuilder.addIngredient(new Sugar(34, 67, "2.00"));
        final Cake chocoMuffin = chocoMuffinBuilder.build();
        chocoMuffin.printResult();
    }
}
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?

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

Friday, February 3, 2012

How to use the "Builder Pattern" in factories?

Using the "Builder Pattern" in Factories making your classes testable

Hi there! In this blog i want show to you how we can combine the builder pattern with the factory pattern making our classes testable. 

Common Problem

In many cases we have (must) separate Domain Objects (DOs) from the objects we use to visualize something in der GUI. For this reason we create in most of the cases Domain Transfer Objects (DTO's) which hold the values from the DO's in it. With a DTO Factory we would be able to create and fill up all attributes of it with default values. This is a good practise because this way we can use the factory to create DTO's also while testing it. That's when the builder pattern comes in. Combining the builder pattern with the factory pattern allow us to create default DTO's as well specific DTO's. Important: If you don't know when the usage of DTO's is appropriate, then you may read this post first: "When do we use DTO's"


UML of the example:


Example Address

Let's say we have the domain object (class) called Address that looks like this:

// Domain Object
public class Address {

    // only a few attributes to show the idea behind it
    private String street;
    private String land;

    public String getStreet() {
        return this.street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getLand() {
        return this.land;
    }

    public void setLand(String land) {
        this.land = land;
    }

}

The DTO could look like this:

public class AddressDTO {

    private Address address;

    public AddressDTO() {
        this.address = new Address();
    }

    public Address getAddress() {
        return this.address;
    }

    public void setAddressDTO(Address address) {
        this.address = address;
    }
}


Then we would also need a mapper. It could look like this:

public class AddressMapper {

    Address domainAddress;
    AddressDTO addressDTO;

    public AddressMapper(Address domainAddress, AddressDTO addressDTO) {
        this.domainAddress = domainAddress;
        this.addressDTO = addressDTO;
    }

    public AddressDTO mapDomainToDto() {
        this.addressDTO.getAddress().setLand(this.domainAddress.getLand());
        this.addressDTO.getAddress().setStreet(this.domainAddress.getStreet());
        return this.addressDTO;
    }

    public Address mapDtoToDomain() {
        this.domainAddress.setLand(this.addressDTO.getAddress().getLand());
        this.domainAddress.setStreet(this.addressDTO.getAddress().getStreet());
        return this.domainAddress;
    }
}

The factory could be implemented like this:

public class AddressDTOFactory {

    private AddressDTO addressDTO;
    private boolean instanceObserver;
    private static AddressDTOFactory factory;

    // factory pattern knows how to create the DTO
    private AddressDTOFactory() {
        super();
        this.instanceObserver = true;
        this.addressDTO = create();
    }

    // singleton pattern instantiates the factory
    public static AddressDTOFactory getInstance() {
        return (factory == null) ? (factory = new AddressDTOFactory()) : factory;
    }

    // public mock values for testing purposes
    public static String DEFAULT_STREET = "MyStreet";
    public static String DEFAULT_LAND = "USA";

    // builder pattern can be used to mock tests
    public AddressDTOFactory street(String street) {
        createNewObjectIfNotObserved();
        this.addressDTO.getAddress().setStreet(street);
        return factory;
    }

    public AddressDTOFactory land(String land) {
        createNewObjectIfNotObserved();
        this.addressDTO.getAddress().setLand(land);
        return factory;
    }

    public AddressDTOFactory defaultFilling() {
        createNewObjectIfNotObserved();
        this.addressDTO.getAddress().setLand(DEFAULT_LAND);
        this.addressDTO.getAddress().setStreet(DEFAULT_STREET);
        return factory;
    }

    public AddressDTOFactory fillMandatoryFields() {
        createNewObjectIfNotObserved();
        // let's assume that land is a mandatory field in GUI and database
        this.addressDTO.getAddress().setLand(DEFAULT_LAND);
        return factory;
    }

    public AddressDTO getObject() {
        if (this.instanceObserver) {
            this.instanceObserver = false;
        } else {
            this.addressDTO = create();
        }
        return this.addressDTO;
    }

    // ensure right instance
    private void createNewObjectIfNotObserved() {
        if (!this.instanceObserver) {
            this.instanceObserver = true;
            this.addressDTO = create();
        }
    }

    private AddressDTO create() {
        return new AddressMapper(new Address(), new AddressDTO()).mapDomainToDto();
    }

}  


Now we have a testable AddressDTO with deterministic character that can be reused for several tests according to your needs. The test could look like this:

import junit.framework.Assert;
import org.junit.Before;
import org.junit.Test;

public class AddressDTOFactoryTest {

    AddressDTO defaultAddressDTO;
    AddressDTO mandatoryAddressDTO;
    AddressDTO emptyAddressDTO;
    AddressDTO customizedAddressDTO;
    AddressDTO totallyEmptyAddressDTO;

    public AddressDTOFactoryTest() {
        super();
    }

    @Before
    public void setUp() throws Exception {
        AddressDTOFactory factory = AddressDTOFactory.getInstance();
        this.defaultAddressDTO = factory.defaultFilling().getObject();
        this.mandatoryAddressDTO = factory.fillMandatoryFields().getObject();
        this.emptyAddressDTO = factory.getObject();
        this.customizedAddressDTO = factory.street("Av. Copacabana").land("Brazil").getObject();
        this.totallyEmptyAddressDTO = factory.getObject();
    }

    @Test
    public void testDefaultAddressDTO() {
        Assert.assertEquals(AddressDTOFactory.DEFAULT_LAND, this.defaultAddressDTO.getAddress().getLand());
        Assert.assertEquals(AddressDTOFactory.DEFAULT_STREET, this.defaultAddressDTO.getAddress().getStreet());
    }

    @Test
    public void testMandatoryAddressDTO() {
        String empty = null;
        Assert.assertEquals(AddressDTOFactory.DEFAULT_LAND, this.mandatoryAddressDTO.getAddress().getLand());
        Assert.assertEquals(empty, this.mandatoryAddressDTO.getAddress().getStreet());
    }

    @Test
    public void testEmptyAddressDTO() {
        String empty = null;
        Assert.assertEquals(empty, this.emptyAddressDTO.getAddress().getLand());
        Assert.assertEquals(empty, this.emptyAddressDTO.getAddress().getStreet());
    }

    @Test
    public void testCustomizedAddressDTO() {
        Assert.assertEquals("Brazil", this.customizedAddressDTO.getAddress().getLand());
        Assert.assertEquals("Av. Copacabana", this.customizedAddressDTO.getAddress().getStreet());
    }

    @Test
    public void testTotallyEmptyAddressDTO() {
        String empty = null;
        Assert.assertEquals(empty, this.totallyEmptyAddressDTO.getAddress().getLand());
        Assert.assertEquals(empty, this.totallyEmptyAddressDTO.getAddress().getStreet());
    }

}

Conclusion


A simple re-adjust or a little more class design can save you a lot of unnecessary, duplicated code and time. It makes the maintenance easier. Think always about how to test it while writing new classes. JUnit tests can be written faster and more consistent. This simple example is a very simplified class. In the real life an Address class is much bigger with a lot more attributes used inside. 



😱👇 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?

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