Showing posts with label singleton. Show all posts
Showing posts with label singleton. Show all posts

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

}