Sunday, August 31, 2014

Creational design patterns in Java

In this post, I'm going to show samples of using creational design patterns in Java.
List of them from wikipedia:
  • Abstract factory pattern, which provides an interface for creating related or dependent objects without specifying the objects' concrete classes.[3]
  • Builder pattern, which separates the construction of a complex object from its representation so that the same construction process can create different representation.
  • Factory method pattern, which allows a class to defer instantiation to subclasses.[4]
  • Prototype pattern, which specifies the kind of object to create using a prototypical instance, and creates new objects by cloning this prototype.
  • Singleton pattern, which ensures that a class only has one instance, and provides a global point of access to it.[5]
Let's consider them closely. 

1. Abstract factory.

Actors: 
 1.abstract factory - interface which defines factory which can be returned.
 2.concrete factory:  concrete class which implements abstract factory and returns implementations of factories.  
Goal: create in one step different objects using different creation classes(factories).
Main class:
public class AbstractFactory {
    
    public static abstract class AbstractShapeFactory {
        public abstract RedShapeFactory getRedShapeFactory();
        public abstract BlackShapeFactory getBlackShapeFactory();
    }
    
    public static abstract class Drawable {
        protected String pattern;
        public Drawable(String pattern) {
            this.pattern=pattern;
        }
        public abstract String createShape(String pattern);
    }
    
    public static class RedShapeFactory extends Drawable {

        public RedShapeFactory(String pattern) {
            super(pattern);
        }

        @Override
        public String createShape(String pattern) {
            return "red "+pattern;          
        }       
    }
    
    public static class BlackShapeFactory extends Drawable {
        public BlackShapeFactory(String pattern) {
            super(pattern);
        }

        @Override
        public String createShape(String pattern) {
            return "black "+pattern;            
        }       
    }
    
    public static class ShapeFactory extends AbstractShapeFactory {
        private final String pattern;
        
        public ShapeFactory(String pattern) {
            this.pattern=pattern;
        }

        @Override
        public RedShapeFactory getRedShapeFactory() {
            return new RedShapeFactory(pattern);
        }

        @Override
        public BlackShapeFactory getBlackShapeFactory() {
            return new BlackShapeFactory(pattern);
        }
        
    }

}


Test class:


import org.junit.Before;
import org.junit.Test;

public class AbstractFactoryTest {
    
    AbstractFactory.ShapeFactory factory;
    String pattern;
    
    @Before
    public void init() {
        pattern="square";
    }

    @Test
    public void blackFactoryTest() {
        factory=new AbstractFactory.ShapeFactory(pattern);
        String result=factory.getBlackShapeFactory().createShape(pattern);
        assertEquals("black square", result);
    }

    @Test
    public void redFactoryTest() {
        factory=new AbstractFactory.ShapeFactory(pattern);
        String result=factory.getRedShapeFactory().createShape(pattern);
        assertEquals("red square", result);
    }
}

2. Factory method

May be the simplest matters: very often developers starts with this pattern and later migrate to more complex solutions.  
Actors: 
1.factory method class with different methods for creation different classes
Goal: 
create in one step different objects using different functions.
Main class:

public class FactoryMethod {
    
    public String createRedSquareStringObject() {
        return "red square";
    }
    
    public String createBlackSquareStringObject() {
        return "black square";
    }

}

Test class:

public class FactoryMethodTest {
    
    private FactoryMethod factory=new FactoryMethod();
    
    @Test
    public void readSquareTest() {
        String shape=factory.createRedSquareStringObject();
        Assert.assertEquals("red square", shape);
    }
    
    @Test
    public void blackSquareTest() {
        String shape=factory.createBlackSquareStringObject();
        Assert.assertEquals("black square", shape);
    }

}

3. Builder

Actors: builder class with methods for adding components to the created object.
Goal: create different objects(with different components) in few steps.
Main class:

public class Builder {
    
    public void addFundament(StringBuilder object) {
        object.append("fundament ");
    } 
    
    public void addFloor(StringBuilder object) {
        object.append("floor ");
    }
    
    public void addMansarda(StringBuilder object) {
        object.append("mansarda");
    }   
    
    public void addRoof(StringBuilder object) {
        object.append("roof");
    }
 
}

Test class:

public class BuilderTest {
    
    private Builder builder=new Builder(); 
    
    @Test
    public void oneFlootBuildingWithRoofTest() {
        StringBuilder building=new StringBuilder();
        
        builder.addFundament(building);
        builder.addFloor(building);
        builder.addRoof(building);
        
        Assert.assertEquals("fundament floor roof", building.toString());
         
    }
    
    @Test
    public void threeFlootBuildingWithMansardaTest() {
        StringBuilder building=new StringBuilder();
        
        builder.addFundament(building);
        builder.addFloor(building);
        builder.addFloor(building);
        builder.addFloor(building);
        builder.addMansarda(building);
        
        Assert.assertEquals("fundament floor floor floor mansarda", building.toString());
         
    }   

}

4.Singleton

Actors: class with static instance 
Goal: only one instance of object can be created and  used by other objects.
Main class:


public enum Singleton {
        INSTANCE;
        
        public String data;
        
}

Test class:

public class SingletonTest {
    
    @Test
    public void test() {
        Singleton s1=Singleton.INSTANCE;
        Singleton s2=Singleton.INSTANCE;
        s1.data="Hello world!";
        Assert.assertEquals(s1.data, s2.data);      
    }
}

5.Prototype

Actors: class which implements Clonable interface
 Goal: sometimes when object has a lot of properties, it's easier to clone object than execute setXXX a lot of times.
Main class:

public class Prototype {
    
    public class ComplexObject implements Cloneable{
                
        private String name;
        private String description;
        private String department;
        
        public ComplexObject(String name, String description, String department) {
            super();
            this.name = name;
            this.description = description;
            this.department = department;
        }
        
        public ComplexObject clone() throws CloneNotSupportedException {
            return (ComplexObject)super.clone();
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getDescription() {
            return description;
        }

        public void setDescription(String description) {
            this.description = description;
        }

        public String getDepartent() {
            return department;
        }

        public void setDepartent(String departent) {
            this.department = departent;
        }
    }
}

Test class:





public class PrototypeTest {
    
    @Test
    public void test() throws CloneNotSupportedException {
        Prototype prototype=new Prototype();
        
        Prototype.ComplexObject complexObject1= prototype. new ComplexObject("name", "description", "departent");
        Prototype.ComplexObject complexObject2=complexObject1.clone();
        
        Assert.assertEquals(complexObject1.getName(), complexObject2.getName());
        Assert.assertEquals(complexObject1.getDescription(), complexObject2.getDescription());
        Assert.assertEquals(complexObject1.getDepartent(), complexObject2.getDepartent());
        
    }

}

No comments:

Post a Comment