Creational
Creational patterns are ones
that create objects for you, rather than having you instantiate objects
directly. This gives your program more flexibility in deciding which objects
need to be created for a given case.
1. Factory Method – creates objects without specifying the exact class to create.
Define an interface for creating an object, but let the classes that implement
the interface decide which class to instantiate. The Factory method lets a
class defer instantiation to subclasses.
interface Pet {
public String speak();
}
class Dog implements Pet {
public String speak() {
return "Bark
bark...";
}
}
class Duck implements Pet {
public String speak() {
return "Quack
quack...";
}
}
class PetFactory {
public Pet getPet(String petType) {
Pet pet
= null;
// based on logic factory instantiates an object
if ("bark".equals(petType))
pet
= new Dog();
else if ("quack".equals(petType))
pet
= new Duck();
return pet;
}
}
public class FactoryMethodExample {
public static void main(String[] args) {
//creating the factory
PetFactory petFactory = new PetFactory();
//factory
instantiates an object
Pet pet = petFactory.getPet("bark");
//you
don't know which object factory created
System.out.println(pet.speak());
}
}
|
Factory method (recognizeable by creational methods returning an implementation
of an abstract/interface type)
·
java.net.URLStreamHandlerFactory#createURLStreamHandler(String)
(Returns
singleton object per protocol)
2. Abstract Factory – groups object factories
that have a common theme.
In the example below, Sea/Land
factories are grouped as AnimalFactory.
Note: Shark and Elephant classes
may not be implementing a common interface but may still be created by
factories that can be grouped by a common abstract factory interface.
interface Animal {
public void breathe();
}
interface AnimalFactory {
public Animal createAnimal();
}
class SeaFactory implements AnimalFactory {
public Animal createAnimal() {
return new Shark();
}
}
class LandFactory implements AnimalFactory {
public Animal createAnimal() {
return new Elephant();
}
}
class Shark implements Animal {
public void breathe() {
System.out.println("I
breathe in water! He he!");
}
}
class Elephant implements Animal {
public void breathe() {
System.out.println("I
breathe with my lungs. Its easy!");
}
}
/**
* Given an animal
factory, creates an animal.
*
* @author Watsh
*
*/
class Wonderland {
public Wonderland(AnimalFactory
factory) {
Animal
animal = factory.createAnimal();
animal.breathe();
}
}
/**
* Test abstract factory
pattern.
*
* @author Watsh
*
*/
public class AbstractFactoryExample {
public static void main(String[] args) {
new Wonderland(createAnimalFactory("water"));
}
public static AnimalFactory
createAnimalFactory(String type) {
if ("water".equals(type))
return new SeaFactory();
else
return new LandFactory();
}
}
|
Abstract factory (recognizeable by creational methods returning the factory itself
which in turn can be used to create another abstract/interface type)
3. Builder - Separate the
construction of a complex object from its representation.
If there are optional properties in
a class then we will have to write several different constructors that can take
different combinations of those optional properties. Instead if we use Builder
pattern we only set the optional properties through their setter methods - thus
keeping the code cleaner.
In the example below,
NutritionalFacts class:
a.
has a static Builder class which takes the
mandatory properties in its constructor,
b.
there are setter methods in Builder for each of
the optional properties.
c.
The setter methods return this instance – for
fluent API.
d.
NutritionalFacts constructor takes Builder and
is private.
class NutritionalFacts {
private int sodium; // mandatory property
// optional properties
private int fat;
private int carbo;
/**
* A nested static class.
*
*/
static class Builder {
private int sodium;
private int fat;
private int carbo;
/**
* Use constructor param for mandatory
properties.
*
* @param s
*/
public Builder(int s) {
this.sodium = s;
}
/*
* Have methods for each property that return
this.
*
* @param f
* @return
*/
public Builder fat(int f) {
this.fat = f;
return this;
}
public Builder carbo(int c) {
this.carbo = c;
return this;
}
public NutritionalFacts build() {
return new NutritionalFacts(this);
}
}
private NutritionalFacts(Builder b) {
this.sodium = b.sodium;
this.fat = b.fat;
this.carbo = b.carbo;
}
@Override
public String toString() {
return "NutritionalFacts
[sodium=" + sodium + ", fat=" + fat
+
", carbo=" + carbo + "]";
}
}
/**
* Builder test.
*
* @author Watsh
*
*/
public class BuilderExample {
public static void main(String[] args) {
NutritionalFacts
n = new NutritionalFacts.Builder(10).carbo(23).fat(1)
.build();
System.out.println(n);
}
}
|
Builder (recognizeable by creational
methods returning the instance itself)
·
java.nio.ByteBuffer#put()
(also
on CharBuffer
, ShortBuffer
, IntBuffer
, LongBuffer
,FloatBuffer
and DoubleBuffer
)
4. Prototype - creates objects by cloning an existing object.
class Bike implements Cloneable {
private int gears;
private String bikeType;
private String model;
public Bike() {
bikeType = "Standard";
model = "Leopard";
gears = 4;
}
public Bike clone() {
return new Bike();
}
public void makeAdvanced() {
bikeType = "Advanced";
model = "Jaguar";
gears = 6;
}
public String getModel() {
return model;
}
@Override
public String toString() {
return "Bike
[gears=" + gears + ", bikeType=" + bikeType + ", model="
+
model + "]";
}
}
public class PrototypeExample {
/**
* Takes a basic bike object and makes an
advanced bike object.
*
* @param basicBike
* @return
*/
public static Bike makeJaguar(Bike basicBike) {
basicBike.makeAdvanced();
return basicBike;
}
public static void main(String[] args) {
Bike
bike = new Bike();
Bike
basicBike = bike.clone();
System.out.println(basicBike);
Bike
advancedBike = makeJaguar(basicBike);
System.out.println("Prototype Design Pattern: " + advancedBike);
}
}
|
Prototype (recognizeable by creational
methods returning a different instance
of itself with the same properties)
5. Singleton - Ensure
a class has only one instance, and provide a global point of access to it.
package patterns.creational;
/**
* Singleton instance
created when class is loaded.
*
* @author Watsh
*
*/
class EagerSingleton {
private static EagerSingleton INSTANCE = new EagerSingleton();
private EagerSingleton() {
}
public static EagerSingleton
getSingleInstance() {
return INSTANCE;
}
}
/**
* This is also lazy
initialization. Only works for Java SE 5.0 or later.
*
*/
class DoubleCheckedLockingSingleton
{
private static DoubleCheckedLockingSingleton INSTANCE = null;
private
DoubleCheckedLockingSingleton() {
}
public static DoubleCheckedLockingSingleton
getSingleInstance() {
if (INSTANCE == null) {
synchronized (DoubleCheckedLockingSingleton.class) {
if (INSTANCE == null) {
INSTANCE = new
DoubleCheckedLockingSingleton();
}
}
}
return INSTANCE;
}
}
/**
* Initialization on-demand holder. The nested class is
referenced no earlier
* (and therefore loaded
no earlier by the class loader) than the moment that
* getInstance() is
called. Thus, this solution is thread-safe without requiring
* special language
constructs (i.e. volatile or synchronized).
*/
class Singleton {
// Private constructor prevents instantiation from other
classes
private Singleton() {
}
/**
* SingletonHolder is loaded on the first
execution of
* Singleton.getInstance() or the first
access to SingletonHolder.INSTANCE,
* not before.
*/
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
/**
* Best approach - does not have the drawback of
serializable objects. Any enum
* value is instantiated
only once in a Java program. Since Java enum values are
* globally accessible,
so is the singleton, initialized lazily by the
* classloader.
*
* @author Watsh
*
*/
enum LazySingleton {
INSTANCE;
public void execute(String arg) {
System.out.println(arg);
}
}
public class SingletonExample {
public static void main(String[] args) {
LazySingleton
in = LazySingleton.INSTANCE;
in.execute("test");
}
}
|
No comments:
Post a Comment