Tuesday, 29 October 2013

Adapter Design pattern - keypoints

🚀 Enjoying Java Tutorials?

Subscribe to Ram N Java for clean, beginner-friendly core Java tutorials and interview prep!

🔔 Subscribe to Ram N Java

Introduction

The Adapter Design Pattern is one of the most frequently asked structural design patterns in technical interviews. It allows two incompatible interfaces to collaborate seamlessly without modifying existing source code. Below is a curated, comprehensive summary of the essential concepts, implementation variations, and interview takeaways you need to know.

1. Intent & Core Purpose

  • Structural Pattern: Adapter is categorized under Gang of Four (GoF) structural design patterns because it concerns class and object composition.
  • Bridge Incompatibility: It converts the interface of a class into another interface that clients expect, letting classes work together that couldn't otherwise due to incompatible interfaces.
  • Also Known As: Wrapper Pattern, because the adapter wraps the existing class (adaptee) inside a compatible layer.

2. The 4 Essential Participants

Participant Role in Architecture
Client Contains the business logic and interacts only via the Target interface.
Target Interface Defines the domain-specific contract and methods that the Client expects to invoke.
Adaptee Existing class or third-party library offering the required functionality under an incompatible interface.
Adapter The intermediate class that implements Target and translates requests to Adaptee method calls.

3. Object Adapter vs. Class Adapter

  • Object Adapter (Composition):
    • Uses object composition by maintaining an instance variable reference to the Adaptee.
    • Implements the Target interface and delegates calls to the composed Adaptee instance.
    • Advantage: Can adapt an Adaptee and any of its subclasses simultaneously. Favors the OOP principle: favor composition over inheritance.
  • Class Adapter (Inheritance):
    • Uses multiple inheritance (in C++) or extends the Adaptee class while implementing the Target interface (in Java).
    • Directly calls inherited superclass methods without creating a separate instance.
    • Trade-off: Commits to a concrete Adaptee class, making it less flexible when working with Adaptee subclasses.

4. When Should You Use It?

  • When you want to reuse an existing class whose interface does not match the one you need.
  • When integrating third-party libraries, legacy components, or APIs whose source code cannot be modified.
  • When building reusable modules that need to coordinate with unrelated or unforeseen classes that don't share compatible interfaces.

5. Real Examples in Java Standard Library

  • java.util.Arrays#asList(): Adapts an array into a standard List interface.
  • java.io.InputStreamReader(InputStream): Adapts a byte stream (InputStream) into a character stream (Reader).
  • java.io.OutputStreamWriter(OutputStream): Adapts a byte stream (OutputStream) into a character stream (Writer).
  • java.util.Collections#enumeration() & list(): Adapts between legacy Enumeration and modern Iterator / Collection interfaces.

Related Tutorials from Ram N Java


Click here to watch in Youtube : https://www.youtube.com/watch?v=mGJRT0TWO5k

Click the below Image to Enlarge


Adapter Design pattern - Real Time Exmaple(Translator)

🚀 Enjoying Java Tutorials?

Subscribe to Ram N Java for clean, beginner-friendly core Java tutorials and interview prep!

🔔 Subscribe to Ram N Java

Introduction

The Adapter Design Pattern is a structural design pattern that allows two incompatible interfaces to communicate seamlessly without modifying their existing behavior. A clear and intuitive real-life analogy to understand this concept is human language translation: communication between two people who speak entirely different languages.

The Communication Problem

Consider two individuals trying to hold a conversation:

  • David (from USA): Speaks and understands only English. He does not know French.
  • Rohit (from France): Speaks and understands only French. He does not know English.

If David wants to communicate with Rohit, or Rohit wants to communicate with David, direct communication is impossible because neither speaks the other's language. Their communication interfaces are incompatible.

The Solution: Introducing John as the Adapter

To resolve this issue, we introduce an intermediary person named John:

  • John knows both English and French fluently.
  • He can listen in English and speak in French, as well as listen in French and speak in English.
  • John acts as the Adapter / Translator bridging David and Rohit.

How the Flow Works

  1. David says "How are you?" in English to John.
  2. John translates "How are you?" into French ("Comment allez-vous?") and passes it to Rohit.
  3. Rohit receives the French message and replies in French ("Très bien, merci") to John.
  4. John translates the French reply back into English ("I am fine, thank you") and speaks it to David.

Through John, David and Rohit converse effectively without either of them having to learn a new language. This is precisely how the Adapter Pattern works in software architecture.

Adapter Pattern Role Mapping

Pattern Role Real-World Participant Role Description
Client David Initiator who understands only English
Target Interface English Interface The language/protocol David expects to interact with
Adaptee Rohit Target receiver who understands only French
Adapter John Translates and converts requests and responses between both parties

Related Tutorials from Ram N Java


Click here to watch in Youtube : https://www.youtube.com/watch?v=hCkFDDPdO-8

Click the below Image to Enlarge

Adapter Design pattern - Real Time Exmaple(Translator)
















See also:

  • Adapter Design pattern - Introduction
  • Adapter Design pattern - Real Time Example (Card Reader)
  • Adapter Design pattern - Real Time Example (Mobile Charger)
  • Adapter Design pattern - Real Time Example (Universal Adaptor)
  • Adapter Design pattern - Real Time Example [JDBC Driver]
  • Adapter Design pattern - Class diagram
  • Adapter Design Pattern - Sequence diagram
  • Adapter Design Pattern - Implementation [Language Translator]
  • Adapter Pattern - Implementation [Object Adapter]
  • Adapter Pattern - Implementation [Class Adapter]
  • Adapter Design Pattern - Implementation [Mobile Charger]
  • Adapter Design Pattern - Key Points
  • All Design Patterns Links
  • Thursday, 17 October 2013

    Prototype Design pattern - Implementation


    Click here to watch in Youtube : https://www.youtube.com/watch?v=nZqoK4uaoZc

    Click the below Image to Enlarge
    Prototype Design pattern - Implementation
    Prototype Design pattern - Implementation - Class Diagram









































    Dogear.java

    public class Dogear
    {
    private int numberOfEars;

    public int getNumberOfEars()
    {
    return numberOfEars;
    }

    public void setNumberOfEars( int numberOfEars )
    {
    this.numberOfEars = numberOfEars;
    }

    @Override
            public String toString()
            {
           return "Dogear [numberOfEars=" + numberOfEars + "]";
            }


    }

    Dogeye.java

    public class Dogeye
    {
    private int numberOfEyes;

    public int getNumberOfEyes()
    {
    return numberOfEyes;
    }

    public void setNumberOfEyes( int numberOfEyes )
    {
    this.numberOfEyes = numberOfEyes;
    }

    @Override
            public String toString()
            {
           return "Dogeye [numberOfEyes=" + numberOfEyes + "]";
            }


    }


    Dogleg.java

    public class Dogleg
    {
    private int numberOflegs;

    public int getNumberOflegs()
    {
    return numberOflegs;
    }

    public void setNumberOflegs( int numberOflegs )
    {
    this.numberOflegs = numberOflegs;
    }

    @Override
            public String toString()
            {
           return "Dogleg [numberOflegs=" + numberOflegs + "]";
            }


    }


    Dogtail.java

    public class Dogtail
    {
    private String tailLength; // long or small

    public String getTailLength()
    {
    return tailLength;
    }

    public void setTailLength( String tailLength )
    {
    this.tailLength = tailLength;
    }

    @Override
            public String toString()
            {
           return "Dogtail [tailLength=" + tailLength + "]";
            }

    }


    Animal.java

    public interface Animal extends Cloneable
    {
     public Animal clone();

    }


    Dog.java

    public class Dog implements Animal
    {

    private String  name;
    private int     age;
    private String  color;
    private Dogleg  dogleg;
    private Dogtail dogtail;
    private Dogear  dogear;
    private Dogeye  dogeye;

    public Dog( String name, int age, String color, Dogleg dogleg, Dogtail dogtail, Dogear dogear, Dogeye dogeye )
    {
    super();
    this.name = name;
    this.age = age;
    this.color = color;
    this.dogleg = dogleg;
    this.dogtail = dogtail;
    this.dogear = dogear;
    this.dogeye = dogeye;
    }

    public Dogleg getDogleg()
    {
    return dogleg;
    }

    public void setDogleg( Dogleg dogleg )
    {
    this.dogleg = dogleg;
    }

    public Dogtail getDogtail()
    {
    return dogtail;
    }

    public void setDogtail( Dogtail dogtail )
    {
    this.dogtail = dogtail;
    }

    public Dogear getDogear()
    {
    return dogear;
    }

    public void setDogear( Dogear dogear )
    {
    this.dogear = dogear;
    }

    public Dogeye getDogeye()
    {
    return dogeye;
    }

    public void setDogeye( Dogeye dogeye )
    {
    this.dogeye = dogeye;
    }

    public String getName()
    {
    return name;
    }

    public void setName( String name )
    {
    this.name = name;
    }

    public int getAge()
    {
    return age;
    }

    public void setAge( int age )
    {
    this.age = age;
    }

    public String getColor()
    {
    return color;
    }

    public void setColor( String color )
    {
    this.color = color;
    }

    public Animal clone()
    {

    Dog dogObject = null;

    try
    {

    dogObject = (Dog) super.clone();

    }

    catch( CloneNotSupportedException e )
    {

    e.printStackTrace();

    }

    return dogObject;
    }

    @Override
    public String toString()
    {
    return "Dog [name=" + name + ", age=" + age + ", color=" + color + ", dogleg=" + dogleg + ", dogtail="
                   + dogtail + ", dogear=" + dogear + ", dogeye=" + dogeye + "]";
    }

    }


    AnimalCache.java

    import java.util.Hashtable;

    public class AnimalCache
    {
    private static Hashtable<String, Animal> AnimalMap = new Hashtable<String, Animal>();

    public static Animal getAnimal( String animalType )
    {
    Dog dog = (Dog) AnimalMap.get(animalType);
    if( dog == null )
    {
    Dogleg dogleg = new Dogleg();
    dogleg.setNumberOflegs(4);

    Dogear dogear = new Dogear();
    dogear.setNumberOfEars(2);

    Dogtail dogtail = new Dogtail();
    dogtail.setTailLength("long");

    Dogeye dogeye = new Dogeye();
    dogeye.setNumberOfEyes(2);

    dog = new Dog("Tommy", 3, "White", dogleg, dogtail, dogear, dogeye);
    AnimalMap.put("dog", dog);
    System.out.println("New Dog Object is created and return\n");
    return dog;
    }
    System.out.println("\nCloned Dog Object is created and return\n");
    return dog.clone();
    }
    }


    PrototypePatternDemo.java

    public class PrototypePatternDemo
    {

    public static void main(String[] args)
    {

    Dog dog = (Dog) AnimalCache.getAnimal("dog");
    displayAnimalProperty(dog);

    Dog cloneddog1 = (Dog) AnimalCache.getAnimal("dog");
    cloneddog1.setName("Jonnie");
    cloneddog1.setAge(4);
    cloneddog1.setColor("Brown");
    displayAnimalProperty(cloneddog1);

    Dog cloneddog2 = (Dog) AnimalCache.getAnimal("dog");
    cloneddog2.setName("Tony");
    cloneddog2.setAge(5);
    cloneddog2.setColor("Brown");
    displayAnimalProperty(cloneddog2);

    Dog cloneddog3 = (Dog) AnimalCache.getAnimal("dog");
    cloneddog3.setName("Jimmy");
    cloneddog3.setAge(8);
    cloneddog3.setColor("Brown");
    displayAnimalProperty(cloneddog3);

    }

    public static void displayAnimalProperty(Animal animal)
    {
    if (animal instanceof Dog)
    {
    Dog dog = (Dog) animal;
    System.out.println(dog.toString());
    System.out.println("-----------------------------------------------------------------------------------------------------");

    }
    }

    }

    Output

    New Dog Object is created and return

    Dog [name=Tommy, age=3, color=White, dogleg=Dogleg [numberOflegs=4], dogtail=Dogtail [tailLength=long], dogear=Dogear [numberOfEars=2], dogeye=Dogeye [numberOfEyes=2]]
    -----------------------------------------------------------------------------------------------------

    Cloned Dog Object is created and return

    Dog [name=Jonnie, age=4, color=Brown, dogleg=Dogleg [numberOflegs=4], dogtail=Dogtail [tailLength=long], dogear=Dogear [numberOfEars=2], dogeye=Dogeye [numberOfEyes=2]]
    -----------------------------------------------------------------------------------------------------

    Cloned Dog Object is created and return

    Dog [name=Tony, age=5, color=Brown, dogleg=Dogleg [numberOflegs=4], dogtail=Dogtail [tailLength=long], dogear=Dogear [numberOfEars=2], dogeye=Dogeye [numberOfEyes=2]]
    -----------------------------------------------------------------------------------------------------

    Cloned Dog Object is created and return

    Dog [name=Jimmy, age=8, color=Brown, dogleg=Dogleg [numberOflegs=4], dogtail=Dogtail [tailLength=long], dogear=Dogear [numberOfEars=2], dogeye=Dogeye [numberOfEyes=2]]
    -----------------------------------------------------------------------------------------------------


    See also:


  • Prototype Design Pattern - Introduction
  • Prototype Design Pattern - Class Diagram
  • Prototype Design Pattern - KeyPoints
  • All Design Patterns Links
  • Prototype Design pattern - keyPoints

    Prototype Design pattern - Class Diagram

    Prototype Design Pattern - Introduction

    Tuesday, 15 October 2013

    Chain of Responsibility Design pattern - Implementation(One or more Rece...



    Click here to watch in Youtube : https://www.youtube.com/watch?v=tyGnCb-kE1I

    Click the below Image to Enlarge
    Chain of Responsibility Design pattern - Implementation
    Chain of Responsibility Design pattern - Implementation - Class Diagram




































    RsHandler.java

    public abstract class RsHandler
    {
    RsHandler rsHandler;

    public void nextHandler( RsHandler rsHandler )
    {
    this.rsHandler = rsHandler;
    }

    public abstract void dispatchRs( long requestedAmount );

    }

    HundredRsHandler.java

    public class HundredRsHandler extends RsHandler
    {

    public void dispatchRs(long requestedAmount)
    {
    long numberofNotesToBeDispatched = requestedAmount / 100;
    if (numberofNotesToBeDispatched > 0)
    {
    if(numberofNotesToBeDispatched>1)
    {
    System.out.println(numberofNotesToBeDispatched + " ,Hundred Rs notes are dispatched by HundredRsHandler\n");
    }
    else
    {
    System.out.println(numberofNotesToBeDispatched + " ,Hundred Rs note is dispatched by HundredRsHandler\n");

    }
    }

    long pendingAmountToBeProcessed = requestedAmount % 100;

    if (pendingAmountToBeProcessed > 0)
    {
    rsHandler.dispatchRs(pendingAmountToBeProcessed);

    }

    }

    }

    FiftyRsHandler.java

    public class FiftyRsHandler extends RsHandler
    {
    public void dispatchRs(long requestedAmount)
    {
    long numberofNotesToBeDispatched = requestedAmount / 50;
    if (numberofNotesToBeDispatched > 0)
    {
    if (numberofNotesToBeDispatched > 1)
    {
    System.out.println(numberofNotesToBeDispatched + " ,Fifty Rs notes are dispatched by FiftyRsHandler\n");
    }
    else
    {
    System.out.println(numberofNotesToBeDispatched + " ,Fifty Rs note is dispatched by FiftyRsHandler\n");

    }

    }

    long pendingAmountToBeProcessed = requestedAmount % 50;

    if (pendingAmountToBeProcessed > 0)
    {
    rsHandler.dispatchRs(pendingAmountToBeProcessed);

    }

    }
    }


    TwentyRsHandler.java

    public class TwentyRsHandler extends RsHandler
    {
    public void dispatchRs(long requestedAmount)
    {
    long numberofNotesToBeDispatched = requestedAmount / 20;

    if (numberofNotesToBeDispatched > 0)
    {

    if (numberofNotesToBeDispatched > 1)
    {
    System.out.println(numberofNotesToBeDispatched + " ,Twenty Rs notes are dispatched by TwentyRsHandler\n");
    }
    else
    {
    System.out.println(numberofNotesToBeDispatched + " ,Twenty Rs note is dispatched by TwentyRsHandler\n");

    }
    }

    long pendingAmountToBeProcessed = requestedAmount % 20;

    if (pendingAmountToBeProcessed > 0)
    {
    rsHandler.dispatchRs(pendingAmountToBeProcessed);

    }

    }
    }


    FiveRsHandler.java

    public class FiveRsHandler extends RsHandler
    {
    public void dispatchRs(long requestedAmount)
    {
    long numberofNotesToBeDispatched = requestedAmount / 5;
    if (numberofNotesToBeDispatched > 0)
    {

    if (numberofNotesToBeDispatched > 1)
    {
    System.out.println(numberofNotesToBeDispatched + " ,Five Rs notes are dispatched by FiveRsHandler\n");
    }
    else
    {
    System.out.println(numberofNotesToBeDispatched + " ,Five Rs note is dispatched by FiveRsHandler\n");

    }
    }

    long pendingAmountToBeProcessed = requestedAmount % 5;

    if (pendingAmountToBeProcessed > 0)
    {
    rsHandler.dispatchRs(pendingAmountToBeProcessed);

    }

    }
    }


    ATM.java

    public class ATM
    {
    private static HundredRsHandler hundredRsHandler = new HundredRsHandler();
    private static FiftyRsHandler   fiftyRsHandler   = new FiftyRsHandler();
    private static TwentyRsHandler  twentyRsHandler  = new TwentyRsHandler();
    private static FiveRsHandler    fiveRsHandler    = new FiveRsHandler();

    static
    {
    // Prepare the chain of Handlers
    hundredRsHandler.nextHandler(fiftyRsHandler);
    fiftyRsHandler.nextHandler(twentyRsHandler);
    twentyRsHandler.nextHandler(fiveRsHandler);
    }

    public void withdraw( long requestedAmount )
    {

    hundredRsHandler.dispatchRs(requestedAmount);
    }
    }


    ChainOfResDemo.java

    public class ChainOfResDemo
    {

    public static void main( String[] args )
    {
    ATM atm = new ATM();
    System.out.println("\n ----------------Requested Amount 475-----------------------\n");
    atm.withdraw(475);
    System.out.println("\n ----------------Requested Amount 455-----------------------\n");
    atm.withdraw(455);
    System.out.println("\n ----------------Requested Amount 520-----------------------\n");
    atm.withdraw(520);
    }

    }


    Output

     ----------------Requested Amount 475-----------------------

    4 ,Hundred Rs notes are dispatched by HundredRsHandler

    1 ,Fifty Rs note is dispatched by FiftyRsHandler

    1 ,Twenty Rs note is dispatched by TwentyRsHandler

    1 ,Five Rs note is dispatched by FiveRsHandler


     ----------------Requested Amount 455-----------------------

    4 ,Hundred Rs notes are dispatched by HundredRsHandler

    1 ,Fifty Rs note is dispatched by FiftyRsHandler

    1 ,Five Rs note is dispatched by FiveRsHandler


     ----------------Requested Amount 520-----------------------

    5 ,Hundred Rs notes are dispatched by HundredRsHandler

    1 ,Twenty Rs note is dispatched by TwentyRsHandler



    Saturday, 12 October 2013

    Chain Of Responsibility Design Pattern - Implementation


    Click here to watch in Youtube : https://www.youtube.com/watch?v=EiU5mIHknGo

    Click the below Image to Enlarge
    Chain Of Responsibility Design Pattern - Implementation

    Chain Of Responsibility Design Pattern - Implementation - Class Diagram


































    Employee.java

    public abstract class Employee
    {

    // next element in chain or responsibility
    protected Employee supervisor;

    public void setNextSupervisor( Employee supervisor )
    {
    this.supervisor = supervisor;
    }

    public abstract void applyLeave( String employeeName, int numberofDaysLeave );
    }


    TeamLeader.java

    public class TeamLeader extends Employee
    {
    // TeamLeader can only approve upto 10 days of leave
    private int MAX_LEAVES_CAN_APPROVE = 10;

    public void applyLeave( String employeeName, int numberofDaysLeave )
    {
     // check if TeamLeader can process this request
    if( numberofDaysLeave <= MAX_LEAVES_CAN_APPROVE )
    {
    ApproveLeave(employeeName, numberofDaysLeave);
    }
     // if TeamLeader can't process the LeaveRequest then pass on to the supervisor(ProjectLeader)
                 // so that he can process
    else
    {
    supervisor.applyLeave(employeeName, numberofDaysLeave);
    }
    }

    private void ApproveLeave( String employeeName, int numberofDaysLeave )
    {
    System.out.println("TeamLeader approved " + numberofDaysLeave + " days " + "Leave for the employee : "
                    + employeeName);

    }
    }

    ProjectLeader.java

    public class ProjectLeader extends Employee
    {
    // ProjectLeader can only approve upto 20 days of leave
    private int MAX_LEAVES_CAN_APPROVE = 20;

    public void applyLeave( String employeeName, int numberofDaysLeave )
    {
     // check if ProjectLeader can process this request
    if( numberofDaysLeave <= MAX_LEAVES_CAN_APPROVE )
    {
    ApproveLeave(employeeName, numberofDaysLeave);
    }
    // if ProjectLeader can't process the LeaveRequest then pass on to the supervisor(HR) 
                 // so that he can process
    else
    {
    supervisor.applyLeave(employeeName, numberofDaysLeave);
    }
    }

    private void ApproveLeave( String employeeName, int numberofDaysLeave )
    {
    System.out.println("ProjectLeader approved " + numberofDaysLeave + " days " + "Leave for the employee : "
                    + employeeName);

    }
    }


    HR.java

    public class HR extends Employee
    {
    // HR can only approve upto 30 days of leave
    private int MAX_LEAVES_CAN_APPROVE = 30;

    public void applyLeave( String employeeName, int numberofDaysLeave )
    {
    if( numberofDaysLeave <= MAX_LEAVES_CAN_APPROVE )
    {
    ApproveLeave(employeeName, numberofDaysLeave);
    }
    else
    {
    System.out.println("Leave application suspended, Please contact HR");
    }
    }

    private void ApproveLeave( String employeeName, int numberofDaysLeave )
    {
    System.out.println("HR approved " + numberofDaysLeave + " days " + "Leave for the employee : "
                    + employeeName);

    }
    }


    ChainPatternDemo.java

    public class ChainPatternDemo
    {

    public static void main( String[] args )
    {
    TeamLeader teamLeader= new TeamLeader();
    ProjectLeader projectLeader= new ProjectLeader();
    HR hr=new HR();
    teamLeader.setNextSupervisor(projectLeader);
    projectLeader.setNextSupervisor(hr);
    teamLeader.applyLeave("David", 9);
    System.out.println();
    teamLeader.applyLeave("John", 18);
    System.out.println();
    teamLeader.applyLeave("Steve", 30);
    System.out.println();
    teamLeader.applyLeave("Rohan", 50);

    }

    }


    Output

    TeamLeader approved 9 days Leave for the employee : David

    ProjectLeader approved 18 days Leave for the employee : John

    HR approved 30 days Leave for the employee : Steve

    Leave application suspended, Please contact HR


    See also:

  • Chain of Responsibility Design Pattern - Introduction
  • Chain of Responsibility Design Pattern - Real time Example
  • Chain of Responsibility Design Pattern - Class and Sequence Diagram
  • Chain of Responsibility Design Pattern - Implementation(one or more Receiver)
  • Chain of Responsibility Design Pattern - Key Points
  • All Design Patterns Links
  • Tutorials