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:
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:
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