Behavioral Patterns
Strategy Pattern
Defines a family of algorithms, encapsulates each, and makes them interchangeable. Context uses a Strategy object to vary its behavior.
Roles:
Strategy: Interface declaring algorithm methodsConcreteStrategy: Implements specific algorithmContext: Maintains strategy reference
Example: E-comerce Discounts
interface PricingStrategy {
double calculatePrice(double price, int quantity);
}
class StandardPricing implements PricingStrategy {
@Override
public double calculatePrice(double price, int quantity) {
return price * quantity;
}
}
class PremiumDiscount implements PricingStrategy {
@Override
public double calculatePrice(double price, int quantity) {
return price * quantity * 0.8;
}
}
class OrderProcessor {
private PricingStrategy strategy;
public OrderProcessor(PricingStrategy strategy) {
this.strategy = strategy;
}
public double processOrder(double price, int quantity) {
return strategy.calculatePrice(price, quantity);
}
}
Command Pattern
Encapsulates a request as an object, allowing parameterization and queuing of requests.
Roles:
Command: Interface for executionConcreteCommand: Binds action to receiverInvoker: Triggers command executionReceiver: Performs actual operations
Example: Restaurent Order System
interface KitchenCommand {
void execute();
void undo();
}
class CookReceiver {
public void prepareDish() {
System.out.println("Cooking dish...");
}
public void cancelPreparation() {
System.out.println("Canceling order...");
}
}
class OrderCommand implements KitchenCommand {
private CookReceiver chef;
public OrderCommand(CookReceiver chef) {
this.chef = chef;
}
@Override
public void execute() {
chef.prepareDish();
}
@Override
public void undo() {
chef.cancelPreparation();
}
}
class WaiterInvoker {
private KitchenCommand command;
public void setCommand(KitchenCommand command) {
this.command = command;
}
public void submitOrder() {
command.execute();
}
}
Template Method Pattern
Defines algorithm skeleton in superclass, allowing subclasses to override specific steps.
Example: Food Delivery
abstract class FoodOrder {
public final void processOrder() {
selectItems();
processPayment();
deliverItems();
optionalTip();
}
abstract void selectItems();
void processPayment() {
System.out.println("Processing payment...");
}
void deliverItems() {
System.out.println("Delivery in progress...");
}
void optionalTip() {}
}
class CoffeeOrder extends FoodOrder {
@Override
void selectItems() {
System.out.println("Selecting coffee items");
}
@Override
void optionalTip() {
System.out.println("Adding tip for delivery");
}
}
Observer Pattern
Defines one-to-many dependency betwean objects. When one changes state, dependents are notified.
Example: State Monitoring
import java.util.*;
interface StateObserver {
void update(int state);
}
class StateSubject {
private List<StateObserver> observers = new ArrayList<>();
private int currentState;
public void attach(StateObserver observer) {
observers.add(observer);
}
public void setState(int state) {
currentState = state;
notifyObservers();
}
private void notifyObservers() {
for (StateObserver o : observers) {
o.update(currentState);
}
}
}
class Display implements StateObserver {
@Override
public void update(int state) {
System.out.println("State changed to: " + state);
}
}
Iterator Pattern
Provides sequential access to elements of aggregate objects.
Example: Student Collection
interface StudentIterator {
boolean hasNext();
Student next();
}
class ClassIterator implements StudentIterator {
private List<Student> students;
private int position;
public ClassIterator(List<Student> list) {
students = list;
}
@Override
public boolean hasNext() {
return position < students.size();
}
@Override
public Student next() {
return students.get(position++);
}
}
class StudentCollection {
private List<Student> students = new ArrayList<>();
public StudentIterator iterator() {
return new ClassIterator(students);
}
public void addStudent(Student s) {
students.add(s);
}
}
Creational Patterns
Singleton Pattern
Ensures single instance existence.
Implementation:
class SystemConfiguration {
private static SystemConfiguration instance;
private SystemConfiguration() {}
public static synchronized SystemConfiguration getInstance() {
if (instance == null) {
instance = new SystemConfiguration();
}
return instance;
}
}
Factory Method Pattern
Delegates object creation to subclasses.
Example: Shape Factory
interface Shape {
void draw();
}
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Drawing circle");
}
}
class ShapeFactory {
public Shape createShape(String type) {
if ("circle".equalsIgnoreCase(type)) {
return new Circle();
}
return null;
}
}
Builder Pattern
Constructs complex objects step-by-step.
Example: Meal Composer
class Meal {
private String mainCourse;
private String side;
private String drink;
// Setters omitted for brevity
}
interface MealBuilder {
void buildMain();
void buildSide();
void buildDrink();
Meal getMeal();
}
class VegMealBuilder implements MealBuilder {
private Meal meal = new Meal();
@Override
public void buildMain() {
meal.setMainCourse("Veg Burger");
}
// Other implementations omitted
}
class MealDirector {
public Meal createMeal(MealBuilder builder) {
builder.buildMain();
builder.buildSide();
builder.buildDrink();
return builder.getMeal();
}
}
Prototype Pattern
Creates objects by cloning prototypes.
Example: Skill Replication
abstract class Ability implements Cloneable {
public abstract Ability cloneAbility();
}
class Fireball extends Ability {
@Override
public Fireball cloneAbility() {
return new Fireball();
}
}
class AbilityManager {
private Ability prototype;
public AbilityManager(Ability prototype) {
this.prototype = prototype;
}
public Ability createAbility() {
return prototype.cloneAbility();
}
}
Structural Patterns
Adapter Pattern
Bridges incompatible interfaces.
Example: Translation Service
interface LocalizationService {
void translate(String text, String targetLanguage);
}
class TranslatorAdaptee {
public void translateText(String text, String lang) {
System.out.println("Translating: " + text + " to " + lang);
}
}
class TranslatorAdapter implements LocalizationService {
private TranslatorAdaptee adaptee = new TranslatorAdaptee();
@Override
public void translate(String text, String target) {
adaptee.translateText(text, target);
}
}
Decorator Pattern
Dynamically adds responsibilities.
Example: Game Character Enhancements
interface Character {
void displaySkills();
}
class Warrior implements Character {
@Override
public void displaySkills() {
System.out.println("Basic warrior skills");
}
}
abstract class SkillDecorator implements Character {
protected Character decoratedCharacter;
public SkillDecorator(Character character) {
decoratedCharacter = character;
}
}
class FireEnchantment extends SkillDecorator {
public FireEnchantment(Character character) {
super(character);
}
@Override
public void displaySkills() {
decoratedCharacter.displaySkills();
System.out.println("Added fire damage");
}
}
Proxy Pattern
Controls access to another object.
Dynamic Proxy Example:
import java.lang.reflect.*;
interface NetworkAccess {
void connect(String url);
}
class RealInternet implements NetworkAccess {
@Override
public void connect(String url) {
System.out.println("Connecting to " + url);
}
}
class AccessHandler implements InvocationHandler {
private Object target;
public AccessHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Access control check");
return method.invoke(target, args);
}
}
class DynamicProxyDemo {
public static void main(String[] args) {
NetworkAccess real = new RealInternet();
NetworkAccess proxy = (NetworkAccess) Proxy.newProxyInstance(
real.getClass().getClassLoader(),
new Class[]{NetworkAccess.class},
new AccessHandler(real)
);
proxy.connect("example.com");
}
}
Facade Pattern
Simplifies complex subsystem interfaces.
Example: Travel Booking
class FlightBooker {
public void bookFlight() { /* Implementation */ }
}
class HotelBooker {
public void bookRoom() { /* Implementation */ }
}
class TravelFacade {
private FlightBooker flightBooker;
private HotelBooker hotelBooker;
public TravelFacade() {
flightBooker = new FlightBooker();
hotelBooker = new HotelBooker();
}
public void arrangeTrip() {
flightBooker.bookFlight();
hotelBooker.bookRoom();
}
}
Bridge Pattern
Decouples abstraction from implementation.
Example: Device Controllers
interface DeviceController {
void operate();
}
class RemoteControl {
protected DeviceController controller;
public RemoteControl(DeviceController controller) {
this.controller = controller;
}
public void execute() {
controller.operate();
}
}
class TVController implements DeviceController {
@Override
public void operate() {
System.out.println("TV operation");
}
}