Follow treslines by email clicking Here!

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. 

How can i motivate other developers ?

Well i do that by talking about, i wear my treslines.com t-shirt, i wear my bracelets with the CCD (Clean Code Developer Initials and colors) and i use my brand new treslines bag. It feels fantastic and even on the train people start talking to me asking about it. It is also a great idea to motivate agile teams and to share your expirience. You may want a great gift to show your appreciation to your team. Surprise them with a gadget from www.treslines.com. I love it.

Other interesting blogs

How could we improve the quality of this article ?

If the content of this article does not help you, so please tell us how to improve the quality of it by giving your contructive feedbacks at the end of this blog. If it was useful to you giving and resuming to you the most important aspects of the subject treated, saving you a lot of time, then help us to maintain this blog with a little appreciation. With a small amount of your choice you help us to cover the prime costs like:
Hosting, autors’s research work, editorial work, blog quality, motivation to make things better than others resulting in a very useful information pool for you and a lot of other developers. Important : If you do not have the possibility to donate a little amount, than recommend this page to your friends. Thanks !





Source code convention tools

Literature, good books and references

How can i subscribe/feed this blog ?

Subscribe : click on the link at the end of this blog

Want to stay up to date ?

How can i rate this blog ?

Press google+1 once !

Where do i find more clean code knowledge and gadgets?

 


4 comments:

  1. IMO, this should be solved at the language level.

    Java can't let you pick fields to initialize in one go without resorting to Builders or making constructors that cover all permutations of field initialization.

    In C#, selective initialization of fields is a first-class feature. So the code above simply becomes:

    AddressData addressData = new AddressData() {
    street = "Street Value",
    land = "Land Value"
    }

    or

    AddressData addressData = new AddressData() {
    street = "Street Value"
    }

    or

    AddressData addressData = new AddressData() {
    land = "Land Value"
    }

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Oh thanks for the comment. there is a missing statement in fillMandatoryFields()/defaultFilling() we shall initialize AddressData first. i will correct it as soon as i can. great comment

    ReplyDelete