Introduction to Software Design Patterns
1. Creational Patterns
Creational design patterns deal with object creation mechanisms. They aim to abstract the instantiation process, making it more flexible and efficient. The main creational patterns include:
1.1 Singleton Pattern The Singleton pattern ensures that a class has only one instance and provides a global point of access to it. This pattern is commonly used in scenarios where a single shared resource is needed, such as database connections or configuration settings.
Example:
javapublic class Singleton { private static Singleton instance; private Singleton() { // private constructor to prevent instantiation } public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
1.2 Factory Method Pattern The Factory Method pattern defines an interface for creating an object but allows subclasses to alter the type of objects that will be created. This pattern helps to delegate the instantiation process to subclasses.
Example:
javapublic abstract class Product { public abstract void use(); } public class ConcreteProductA extends Product { public void use() { System.out.println("Using ConcreteProductA"); } } public class ConcreteProductB extends Product { public void use() { System.out.println("Using ConcreteProductB"); } } public abstract class Creator { public abstract Product factoryMethod(); } public class ConcreteCreatorA extends Creator { public Product factoryMethod() { return new ConcreteProductA(); } } public class ConcreteCreatorB extends Creator { public Product factoryMethod() { return new ConcreteProductB(); } }
2. Structural Patterns
Structural design patterns deal with object composition. They help ensure that if one part of a system changes, the entire system does not need to change. These patterns include:
2.1 Adapter Pattern The Adapter pattern allows incompatible interfaces to work together. It acts as a bridge between two incompatible interfaces.
Example:
javapublic interface Target { void request(); } public class Adaptee { public void specificRequest() { System.out.println("Specific request"); } } public class Adapter implements Target { private Adaptee adaptee; public Adapter(Adaptee adaptee) { this.adaptee = adaptee; } public void request() { adaptee.specificRequest(); } }
2.2 Composite Pattern The Composite pattern allows you to compose objects into tree structures to represent part-whole hierarchies. This pattern treats individual objects and compositions of objects uniformly.
Example:
javaimport java.util.ArrayList; import java.util.List; public interface Component { void operation(); } public class Leaf implements Component { public void operation() { System.out.println("Leaf operation"); } } public class Composite implements Component { private List
children = new ArrayList<>(); public void add(Component component) { children.add(component); } public void remove(Component component) { children.remove(component); } public void operation() { for (Component child : children) { child.operation(); } } }
3. Behavioral Patterns
Behavioral design patterns focus on communication between objects, what goes on between objects and how they operate together. Key patterns in this category include:
3.1 Observer Pattern The Observer pattern defines a one-to-many dependency between objects, so when one object changes state, all its dependents are notified and updated automatically.
Example:
javaimport java.util.ArrayList; import java.util.List; public interface Subject { void attach(Observer observer); void detach(Observer observer); void notifyObservers(); } public interface Observer { void update(); } public class ConcreteSubject implements Subject { private List
observers = new ArrayList<>(); private int state; public void setState(int state) { this.state = state; notifyObservers(); } public int getState() { return state; } public void attach(Observer observer) { observers.add(observer); } public void detach(Observer observer) { observers.remove(observer); } public void notifyObservers() { for (Observer observer : observers) { observer.update(); } } } public class ConcreteObserver implements Observer { private ConcreteSubject subject; public ConcreteObserver(ConcreteSubject subject) { this.subject = subject; this.subject.attach(this); } public void update() { System.out.println("State updated to: " + subject.getState()); } }
3.2 Strategy Pattern The Strategy pattern defines a family of algorithms, encapsulates each algorithm, and makes them interchangeable. The Strategy pattern allows a client to choose an algorithm at runtime.
Example:
javapublic interface Strategy { int execute(int a, int b); } public class AddStrategy implements Strategy { public int execute(int a, int b) { return a + b; } } public class SubtractStrategy implements Strategy { public int execute(int a, int b) { return a - b; } } public class Context { private Strategy strategy; public Context(Strategy strategy) { this.strategy = strategy; } public int executeStrategy(int a, int b) { return strategy.execute(a, b); } }
Conclusion
Software design patterns offer time-tested solutions to common problems, providing a template for software design that improves code readability, reusability, and maintainability. By understanding and applying these patterns, developers can create more robust and flexible software solutions. Whether you are dealing with object creation, structuring, or behavior management, design patterns provide a foundational approach to solving complex issues in a systematic way.
Popular Comments
No Comments Yet