Design patterns are proven solutions to common problems in software design. They provide an established approach to designing application architecture, making the process easier and more efficient. In Java, design patterns are categorized into three primary groups: Creational, Structural, and Behavioral patterns. This post specifically explores Creational Design Patterns, which focus on object creation mechanisms, trying to create objects in a manner suitable for the situation.
What Are Creational Design Patterns?
Creational Design Patterns abstract the instantiation process while increasing flexibility and reuse of existing code. They deal with the way of creating objects, allowing the design to be more independent from the specific classes of objects that it creates.
Common Creational Patterns
Some of the well-known Creational Design Patterns in Java include:
- Singleton Pattern: Ensures that a class has only one instance and provides a global point of access to it.
- Factory Method Pattern: Defines an interface for creating an object, but lets subclasses alter the type of objects that will be created.
- Abstract Factory Pattern: Provides an interface for creating families of related or dependent objects without specifying their concrete classes.
- Builder Pattern: Allows for the step-by-step creation of complex objects.
- Prototype Pattern: Enables cloning of existing objects, allowing customization of the clone before it is used.
1. Singleton Pattern
The Singleton Pattern is used when you need to restrict the instantiation of a class to a single instance. This is useful when exactly one object is needed to coordinate actions across the system.
public class Singleton {
// Static variable that holds the single instance
private static Singleton instance;
// Private constructor to prevent instantiation
private Singleton() {}
// Public method to provide access to the instance
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
2. Factory Method Pattern
The Factory Method Pattern defines an interface for creating an object, but it is up to the subclasses to decide which class to instantiate. This promotes loose coupling by eliminating the need to bind application-specific classes into your code.
// Product Interface
interface Product {
void create();
}
// Concrete Product
class ConcreteProductA implements Product {
public void create() {
System.out.println("Product A Created");
}
}
class ConcreteProductB implements Product {
public void create() {
System.out.println("Product B Created");
}
}
// Creator
abstract class Creator {
public abstract Product factoryMethod();
public void someOperation() {
Product product = factoryMethod();
product.create();
}
}
// Concrete Creator
class ConcreteCreatorA extends Creator {
public Product factoryMethod() {
return new ConcreteProductA();
}
}
class ConcreteCreatorB extends Creator {
public Product factoryMethod() {
return new ConcreteProductB();
}
}
3. Abstract Factory Pattern
The Abstract Factory Pattern provides an interface to create families of related or dependent objects without specifying their concrete classes. This pattern is particularly useful when the system needs to be independent of how its objects are created, composed, and represented.
// Abstract Factory Interface
interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}
// Product Interfaces
interface ProductA {
void use();
}
interface ProductB {
void utilize();
}
// Concrete Factories
class ConcreteFactory1 implements AbstractFactory {
public ProductA createProductA() {
return new ConcreteProductA1();
}
public ProductB createProductB() {
return new ConcreteProductB1();
}
}
class ConcreteFactory2 implements AbstractFactory {
public ProductA createProductA() {
return new ConcreteProductA2();
}
public ProductB createProductB() {
return new ConcreteProductB2();
}
}
4. Builder Pattern
The Builder Pattern is used to construct complex objects step by step. It allows you to create different representations of an object using the same construction process.
class Product {
private String part1;
private String part2;
public void setPart1(String part) { this.part1 = part; }
public void setPart2(String part) { this.part2 = part; }
}
class Builder {
private Product product = new Product();
public Builder addPart1(String part) {
product.setPart1(part);
return this;
}
public Builder addPart2(String part) {
product.setPart2(part);
return this;
}
public Product build() {
return product;
}
}
5. Prototype Pattern
The Prototype Pattern creates new objects by copying an existing object, known as the prototype. This is particularly useful when creating complex objects is resource-intensive.
import java.util.HashMap;
import java.util.Map;
interface Prototype {
Prototype clone();
}
class ConcretePrototype implements Prototype {
private String name;
public ConcretePrototype(String name) {
this.name = name;
}
public Prototype clone() {
return new ConcretePrototype(name);
}
}
Conclusion
Creational Design Patterns are fundamental in software design, facilitating object creation while promoting loose coupling and reusability. By incorporating these patterns into your Java applications, you can significantly enhance the flexibility and scalability of your code. Understanding when and how to apply these patterns is crucial for developing effective Java applications.
Want to learn more about Java Core? Join the Java Core in Practice course now!