What are design patterns?
Design patterns are proven solutions to common problems in software design. They represent best practices used by experienced software developers to solve recurring design issues. Design patterns provide a template for how to solve a problem that can be used in many different situations. They are not complete code, but rather concepts and strategies for structuring code to make it more modular, flexible, and reusable.
Table of Contents
There are three types of design patterns. advantages of Java Design Patterns
1) Creational Patterns.
2) Structural Patterns:
3) Behavioral Patterns:
Advantages of Java Design Patterns
1. Reusability: Design patterns provide a reusable solution that can be applied to various parts of the application, saving time and effort.
2. Maintainability: They improve the maintainability of the code by promoting a well-structured and organized architecture.
3. Communication: Design patterns provide a common vocabulary for designers and developers, making it easier to discuss and collaborate on software design.
4. Best Practices: Using design patterns ensures that the code follows industry best practices and principles, leading to better-quality software.
5. Flexibility and Scalability: They help create systems that are more flexible and scalable by defining clear roles and interactions for different components.
Types of Design Patterns in Java
Design patterns in Java are categorized into three types: Creational Patterns, Structural Patterns, and Behavioral Patterns.
1. Creational Patterns
- These patterns deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. They help make a system independent of how its objects are created, composed, and represented.
- Examples: Singleton, Factory Method, Abstract Factory, Builder, Prototype
java
public 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;
}
public void showMessage() {
System.out.println("Hello from Singleton!");
}
}
public class SingletonPatternDemo {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
singleton.showMessage();
}
}
2) Structural Patterns
These patterns deal with object composition or how classes and objects can be composed to form larger structures. They help ensure that if one part of a system changes, the entire system doesn’t need to change.
Examples: Adapter, Composite, Proxy, Flyweight, Facade, Bridge, Decorator
Example - Adapter Pattern:
java
interface MediaPlayer {
void play(String audioType, String fileName);
}
class AudioPlayer implements MediaPlayer {
MediaAdapter mediaAdapter;
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("mp3")) {
System.out.println("Playing mp3 file. Name: " + fileName);
} else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType, fileName);
} else {
System.out.println("Invalid media. " + audioType + " format not supported");
}
}
}
interface AdvancedMediaPlayer {
void playVlc(String fileName);
void playMp4(String fileName);
}
class VlcPlayer implements AdvancedMediaPlayer {
@Override
public void playVlc(String fileName) {
System.out.println("Playing vlc file. Name: " + fileName);
}
@Override
public void playMp4(String fileName) {
// do nothing
}
}
class Mp4Player implements AdvancedMediaPlayer {
@Override
public void playVlc(String fileName) {
// do nothing
}
@Override
public void playMp4(String fileName) {
System.out.println("Playing mp4 file. Name: " + fileName);
}
}
class MediaAdapter implements MediaPlayer {
AdvancedMediaPlayer advancedMusicPlayer;
public MediaAdapter(String audioType) {
if (audioType.equalsIgnoreCase("vlc")) {
advancedMusicPlayer = new VlcPlayer();
} else if (audioType.equalsIgnoreCase("mp4")) {
advancedMusicPlayer = new Mp4Player();
}
}
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("vlc")) {
advancedMusicPlayer.playVlc(fileName);
} else if (audioType.equalsIgnoreCase("mp4")) {
advancedMusicPlayer.playMp4(fileName);
}
}
}
public class AdapterPatternDemo {
public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "beyond the horizon.mp3");
audioPlayer.play("mp4", "alone.mp4");
audioPlayer.play("vlc", "far far away.vlc");
audioPlayer.play("avi", "mind me.avi");
}
}
3. Behavioral Patterns
These patterns are concerned with algorithms and the assignment of responsibilities between objects. They help in managing how objects interact and communicate with each other.
Examples: Strategy, Observer, Command, Iterator, Mediator, Memento, State, Template Method, Visitor, Chain of Responsibility
Example - Observer Pattern:
java
import java.util.ArrayList;
import java.util.List;
interface Observer {
void update(String message);
}
class Subject {
private List<Observer> observers = new ArrayList<>();
private String message;
public void attach(Observer observer) {
observers.add(observer);
}
public void notifyAllObservers() {
for (Observer observer : observers) {
observer.update(message);
}
}
public void setMessage(String message) {
this.message = message;
notifyAllObservers();
}
}
class ConcreteObserver implements Observer {
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + " received message: " + message);
}
}
public class ObserverPatternDemo {
public static void main(String[] args) {
Subject subject = new Subject();
Observer observer1 = new ConcreteObserver("Observer 1");
Observer observer2 = new ConcreteObserver("Observer 2");
subject.attach(observer1);
subject.attach(observer2);
subject.setMessage("Hello, Observers!");
}
}
Summary
Design patterns are essential tools in software development, providing reusable solutions for common problems. They improve code quality, reusability, maintainability, and communication among developers. Java design patterns are categorized into Creational, Structural, and Behavioral patterns, each serving different purposes and addressing various design challenges. The provided examples demonstrate how these patterns can be implemented in Java to solve specific design problems effectively.