Wednesday, 25 June 2025

 

State Design Pattern

The State Design Pattern is a behavioral design pattern that lets an object change its behavior when its internal state changes. It appears as if the object changed its class.


๐Ÿง  Key Concepts

Concept

Description

Context

The object whose behavior changes depending on its state

State

An interface that defines common behavior for all states

ConcreteState

Classes that implement the State interface with specific behavior


๐Ÿงพ Problem It Solves

Without the State pattern, you might have code like this:

if (state.equals("RED")) {

    stop();

} else if (state.equals("GREEN")) {

    go();

}

This becomes harder to maintain as you add more states and behaviors.


๐Ÿšฆ Example: Traffic Light System

A traffic light can be in 3 states:

  • ๐Ÿ”ด Red – Cars must stop.
  • ๐ŸŸข Green – Cars can go.
  • ๐ŸŸก Yellow – Cars should slow down.

The light should change from:

➡️ Red → Green → Yellow → Red → ...

 

 

 

ADVANTAGES OF STATE PATTERN

Benefit

Description

Removes complex if-else logic

Each state has its own class

Easy to add new states

Just create a new class implementing State

Promotes Open/Closed Principle

Classes are open for extension, closed for modification


⚠️ DISADVANTAGES

Drawback

Description

More classes to manage

One class per state can be a lot in large systems

Overhead for simple state logic

Sometimes an enum + switch is simpler


๐Ÿ When to Use the State Pattern

  • When an object must change behavior based on its state
  • When there are many conditionals based on the state
  • When the state transitions are complex or likely to grow

 

 

Exmple:1

 

package statedesignpattern;

 

public interface State {

               void handleRequest();

}

 

 

 

 

 

package statedesignpattern;

 

public class DraftState implements State {

 

               @Override

               public void handleRequest() {

                              System.out.println("Document is in Draft state.");

 

               }

 

}

 

 

package statedesignpattern;

 

public class ModerationState implements State{

 

               @Override

               public void handleRequest() {

                               System.out.println("Document is under Moderation.");

                             

               }

 

}

 

 

package statedesignpattern;

 

public class PublishState implements State {

 

               @Override

               public void handleRequest() {

                              System.out.println("Document is Published.");

 

               }

 

}

 

package statedesignpattern;

 

public class DocumentContext {

 

               private State currentState;

 

               public DocumentContext() {

                              // default state

                              this.currentState = new DraftState();

               }

 

               public void setState(State state) {

                              this.currentState = state;

               }

 

               public void applyState() {

                              currentState.handleRequest();

               }

              

              

              

 

}

 

 

 

package statedesignpattern;

 

public class Main {

               public static void main(String[] args) {

                              DocumentContext context = new DocumentContext();

 

                              context.applyState(); // Draft

 

                              context.setState(new ModerationState());

                              context.applyState(); // Moderation

 

                              context.setState(new PublishState());

                              context.applyState(); // Published

               }

}

 

o/p:

Document is in Draft state.

Document is under Moderation.

Document is Published.

 

Example :2

package statedesignpattern.trafficlightexample;

 

public interface State {

 

               void handle(TrafficLightContext context);

              

}

 

package statedesignpattern.trafficlightexample;

 

public class RedLightState implements State {

 

               @Override

               public void handle(TrafficLightContext context) {

                               System.out.println("๐Ÿ”ด Red Light - STOP");

                       context.setState(new GreenLightState());

                             

               }

 

}

 

package statedesignpattern.trafficlightexample;

 

public class GreenLightState implements State{

 

               @Override

               public void handle(TrafficLightContext context) {

                              System.out.println("๐ŸŸข Green Light - GO");

        context.setState(new YellowLightState());

                             

               }

 

}

 

package statedesignpattern.trafficlightexample;

 

public class YellowLightState implements State {

 

               @Override

               public void handle(TrafficLightContext context) {

                               System.out.println("๐ŸŸก Yellow Light - SLOW DOWN");

                       context.setState(new RedLightState());

                             

               }

 

}

 

package statedesignpattern.trafficlightexample;

 

public class TrafficLightContext {

 

               private State currentState;

 

               public TrafficLightContext() {

                              this.currentState = new RedLightState();// Initial state

               }

 

               public void setState(State state) {

                              this.currentState = state;

               }

 

               public void change() {

                              currentState.handle(this);

               }

}

 

 

package statedesignpattern.trafficlightexample;

 

public class Main {

 

               public static void main(String[] args) {

 

                              TrafficLightContext trafficLightContext = new TrafficLightContext();

                              for (int i = 0; i < 6; i++) {

                                             trafficLightContext.change();

 

                                             try {

                                                            Thread.sleep(1000); // simulate delay

                                             } catch (InterruptedException e) {

                                                            e.printStackTrace();

                                             }

                              }

 

               }

}

 

o/p:

 

๐Ÿ”ด Red Light - STOP

๐ŸŸข Green Light - GO

๐ŸŸก Yellow Light - SLOW DOWN

๐Ÿ”ด Red Light - STOP

๐ŸŸข Green Light - GO

๐ŸŸก Yellow Light - SLOW DOWN

 

 

 

 

 

 


 

                                                                  Iterator Design Pattern

The Iterator Design Pattern is one of the behavioral design patterns. It provides a standard way to traverse or iterate through a collection of objects (like lists, trees, or other data structures) without exposing the underlying representation of the collection.

Intent

  • To access elements of a collection sequentially without exposing its underlying representation.

Key Components

  1. Iterator (Interface)
    • Defines the interface for accessing and traversing elements.
    • Example methods: hasNext(), next()
  2. Concrete Iterator
    • Implements the Iterator interface.
    • Keeps track of the current position in the traversal.
  3. Aggregate / Collection (Interface)
    • Defines the interface for creating an iterator object.
  4. Concrete Aggregate
    • Implements the Aggregate interface.
    • Returns an instance of the concrete iterator.

๐Ÿ“˜ Advantages

  • Hides the internal structure of collections.
  • Provides a uniform interface for traversing different collection types.
  • Supports multiple simultaneous iterations on the same collection.

⚠️ Disadvantages

  • Adds complexity in custom collections.
  • Might lead to overhead if used in simple structures.

Java Built-in Support

Java provides built-in support for this pattern through the Iterator interface found in the java.util package.

Iterator<String> iterator = list.iterator();

while (iterator.hasNext()) {

    String element = iterator.next();

    System.out.println(element);

}

 

 

Example :

Step 1: Create the Iterator interface

package iteratordesignpattern;

 

public interface Iterator {

               boolean hasNext(); 

    Object next();

}

 

Step 2: Create the Container interface

 

package iteratordesignpattern;

 

public interface Container {

 

               Iterator getItertaor();

}

 

 

 

Step 3: Create NameRepository class

package iteratordesignpattern;

public class NameRepository implements Container {

               public String[] names = { "Govind", "Ballabh", "Khan", "Java", "Technology" };

 

               @Override

               public Iterator getItertaor() {

                              // TODO Auto-generated method stub

                               return new NameIterator();

               }

               private class NameIterator implements Iterator {

                              int index;

 

                              @Override

                              public boolean hasNext() {

                                             // TODO Auto-generated method stub

                                             return index < names.length;

                              }

 

                              @Override

                              public Object next() {

                                             if (this.hasNext()) {

                                                            return names[index++];

                                             }

                                             return null;

                              }

 

               }

 

}

 

Step 4: Test the Iterator

package iteratordesignpattern;

 

public class IteratorPatternDemo {

               public static void main(String[] args) {

                              NameRepository nameRepository = new NameRepository();

 

                              for (Iterator iterator = nameRepository.getItertaor(); iterator.hasNext();) {

          String name = (String)iterator.next();

          System.out.println(name);

                              }

               }

}

 

 

o/p:

Govind

Ballabh

Khan

Java

Technology

 

Example :2

 

package iteratordesignpattern;

 

public class Book {

 

               private String title;

               private String author;

 

               public Book(String title, String author) {

                              super();

                              this.title = title;

                              this.author = author;

               }

 

               public String getTitle() {

                              return title;

               }

 

               public void setTitle(String title) {

                              this.title = title;

               }

 

               public String getAuthor() {

                              return author;

               }

 

               public void setAuthor(String author) {

                              this.author = author;

               }

 

}

 

 

 

 

 

package iteratordesignpattern;

 

public interface Iterator {

               boolean hasNext(); 

    Object next();

}

 

 

 

package iteratordesignpattern;

 

public interface Container {

 

               Iterator getItertaor();

}

 

 

 

 

package iteratordesignpattern;

 

public class BookRepository implements Container {

 

               private int count = 0;

               private Book[] books;

 

               public BookRepository(int size) {

                              books = new Book[size];

               }

 

               public void addBook(Book book) {

                              if (count < books.length) {

                                             books[count] = book;

                                             count++;

                              }

               }

 

               @Override

               public Iterator getItertaor() {

                              return new BookIterator();

 

               }

 

               public class BookIterator implements Iterator {

                              private int index = 0;

 

                              @Override

                              public boolean hasNext() {

                                             // TODO Auto-generated method stub

                                             return index < count && books[index] != null;

                              }

 

                              @Override

                              public Object next() {

                                             if (this.hasNext()) {

                                                            return books[index++];

                                             }

                                             return null;

                              }

 

               }

 

}

 

 

package iteratordesignpattern;

 

public class BookIteratorDemo {

 

               public static void main(String[] args) {

                              BookRepository bookRepository = new BookRepository(5);

                              bookRepository.addBook(new Book("OS", "Galvin"));

                              bookRepository.addBook(new Book("Java", "Durga Sir"));

                              bookRepository.addBook(new Book("C++", "Yashwantkanetkar"));

 

                              Iterator iterator = bookRepository.getItertaor();

 

                              while (iterator.hasNext()) {

                                             Book book = (Book) iterator.next();

                                             System.out.println("Book: " + book.getTitle() + ", Author: " + book.getAuthor());

                              }

               }

}

 

 

 

o/p:

 

Book: OS, Author: Galvin

Book: Java, Author: Durga Sir

Book: C++, Author: Yashwantkanetkar

 

 

 

 

Friday, 20 June 2025

 

Decorator Pattern

The Decorator Pattern is a structural design pattern that lets you attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

In Java, the Decorator Pattern is used to wrap objects in decorator classes that add new behaviors or responsibilities without changing the original object's code.

 

Intent

  • Attach additional responsibilities to an object dynamically.
  • Provide a flexible alternative to subclassing for extending functionality.
  • Keep the core object and its extensions separate.
  • Enable adding features transparently to clients.

Participants

The main participants in the Decorator Pattern are:

a. Component (interface or abstract class)

  • Defines the interface for objects that can have responsibilities added to them dynamically.
  • Example: Text interface with getContent() method.

b. ConcreteComponent (implements Component)

  • The core object to which additional responsibilities can be attached.
  • Example: SimpleText class that implements Text.

c. Decorator (abstract class or interface implementing Component)

  • Maintains a reference to a Component object.
  • Implements the Component interface.
  • Delegates operations to the wrapped component.
  • Acts as a base class for concrete decorators.

d. ConcreteDecorator (extends Decorator)

  • Adds responsibilities to the component.
  • Overrides component methods to provide extra behavior.
  • Example: UpperCaseDecorator and StarDecorator.

 

Uml

 

 

How it Works

  • The client interacts with objects through the Component interface.
  • A ConcreteComponent is created, which implements the basic behavior.
  • To add functionality, a Decorator wraps the ConcreteComponent.
  • Multiple decorators can wrap the same component to combine behaviors.
  • Decorators forward requests to the wrapped component, adding extra processing before or after forwarding.

Benefits (Advantages)

  • Open/Closed Principle: You can add new behavior without modifying existing code.
  • Flexible extension: New functionality can be added at runtime.
  • Avoids an explosion of subclasses by combining decorators instead of subclassing.
  • Can wrap multiple decorators to compose complex behavior.
  • Transparent to the client — clients use decorated objects via the same interface.

Drawbacks (Disadvantages)

  • Can produce a large number of small classes.
  • The design can become complex if many decorators are stacked.
  • Debugging can be harder because of many layers of wrapping.
  • Slight performance overhead due to multiple levels of indirection.

Typical Use Cases in Java

  • Adding features to streams (java.io package uses Decorator pattern extensively: BufferedReader, InputStreamReader).
  • GUI frameworks for adding borders, scrollbars, or behaviors to components.
  • Adding responsibilities such as logging, caching, validation dynamically.
  • Adding filters or transformations to data streams or collections.

 

Real-world Example (Java IO)

Java’s IO library is a classic example of the Decorator Pattern:

  • InputStream is the Component.
  • FileInputStream is a ConcreteComponent.
  • BufferedInputStream is a Decorator adding buffering.
  • DataInputStream is another Decorator adding data-type reading.

You can wrap a FileInputStream inside a BufferedInputStream and then wrap that in a DataInputStream to combine functionalities dynamically.

InputStream file = new FileInputStream("file.txt");

InputStream buffer = new BufferedInputStream(file);

DataInputStream data = new DataInputStream(buffer);

 

int value = data.readInt();

Summary

Aspect

Description

Pattern Type

Structural

Purpose

Add responsibilities dynamically

Key Principle

Composition over inheritance

Key Benefit

Flexible, reusable, open to extension

Main Components

Component, ConcreteComponent, Decorator, ConcreteDecorator

Common Usage

Java IO, GUI component decoration

 

 

 

Example : -

Component

package decoratordesignpattern;

 

public interface Text {

               String getContent();

}

 

ConcreteComponent

 

 

package decoratordesignpattern;

 

public class SimpleText implements Text {

 

               private String content;

 

               public SimpleText(String content) {

                              super();

                              this.content = content;

               }

 

               @Override

               public String getContent() {

                              return content;

               }

 

}

 

 

Decorator

 

package decoratordesignpattern;

 

public abstract class TextDecorator implements Text {

 

               protected Text decoratedText;

 

               public TextDecorator(Text decoratedText) {

                              super();

                              this.decoratedText = decoratedText;

               }

 

               @Override

               public String getContent() {

                              return decoratedText.getContent();

               }

}

 

 

 

ConcreteDecorator

 

package decoratordesignpattern;

 

public class UpperCaseDecorator extends TextDecorator {

 

               public UpperCaseDecorator(Text decoratedText) {

                              super(decoratedText);

 

               }

 

               public String getContent() {

                              return decoratedText.getContent().toUpperCase();

               }

 

}

 

 

package decoratordesignpattern;

 

public class StarDecorator extends TextDecorator {

 

               public StarDecorator(Text decoratedText) {

                              super(decoratedText);

                              // TODO Auto-generated constructor stub

               }

 

               @Override

               public String getContent() {

                              return "*** " + decoratedText.getContent() + " ***";

               }

 

}

 

 

 

package decoratordesignpattern;

 

public class DecoratorDemo {

 

               public static void main(String[] args) {

 

                              Text myText = new SimpleText("Hello World!");

 

                              // Wrap with uppercase decorator

                              Text upper = new UpperCaseDecorator(myText);

                              System.out.println(upper.getContent()); // Output: HELLO, WORLD!

 

                              // Wrap with star decorator

                              Text starred = new StarDecorator(myText);

                              System.out.println(starred.getContent()); // Output: *** Hello, world! ***

 

                              // Combine decorators (starred + uppercase)

                              Text starredUpper = new StarDecorator(upper);

                              System.out.println(starredUpper.getContent()); // Output: *** HELLO, WORLD! ***

 

               }

}

 

 

 

o/p :-

HELLO WORLD!

*** Hello World! ***

*** HELLO WORLD! ***