Introduction to Adapter Pattern( Java, DotNet example)

In this article we are going to learn about a very easy Design Pattern, Adapter Pattern. What is Adapter pattern? What are the basic principles? How to implement and where we can use this.
I have used Java with Eclipse and C# with VS2010.

What is Adapter Design Pattern?
By the name we can have some idea about this very easy pattern Adapter. Adapter design pattern allows us to use a class which is not compatible with exist system by providing adaptability. More easily, adapter pattern let clients to use any incompatible( not accepted) class/interface. It allows to access to incompatible interface work together.

Think like as , we have a micro SD card used in mobile and we have a camera who uses SD card. So, we use an microSD to SD card adapter to use out mobile memory card in to camera. We insert microSD card in adapter and directly adapter used by our client camera(who actually expects SD card). 

Let say, we have a washing system where a client can clean cloths using SOAP. And we have criteria for a what soap is accepted by washing machine. Now, let say we get a new detergent. So, we need an adapter that makes the detergent work as soap inside washing machine.

Now, lets think about the problem in development prospective. We have a situation where our existing system( our client) accepts an interface to perform some task. And we need to introduce a class/interface do similar work but it does not implement that interface. And , we can not change the interface or even the class from code. So, we have to make an intermediate class that keeps both interface and the class intact but allow client to use that class. So , this is the adapter. Generally adapter accepts a class to make it compatible with client.  Client -> Adapter[Class]

So, in adapter pattern there will be mainly 4 elements
1. An Interface which is actually act as target for adaptation. Client use this interface to call for the function. And , adapter makes our class compatible for the interface so that client call is successful.

2. A subject class/interface which will be adaptable for the system . It is call Adaptee( previously I have mentioned as the class).

3. An adapter class who actually make the adaptee class compatible for client who calls this adapter using the target interface. It means adapter-adaptee as whole work together for client like as normal class. And, Usually adapter contains an adaptee inside(composition) to make it compatible

4. The client, who calls the adapter by the target interface and make that workable.

Note : We have to think logically about what can be compatible to the system. Only a similar functionality provider are the best candidate for adaptee. That means the logical candidate, not every object

Basic Principles :
- Converts the class into another class(or one interface to another interface that the client expects)
- Let the incompatible classes work together. 

UML : 

How to implement?
Let's think about how to implement. Usually a system will have interface. And we have to convert our new(or coming from another system) interface /class in the system's interface. And we can not change any one (not target not adaptee).
Client used to call its system exist objects by the Interface (target interface) so client will call our adapter by the interface.
That means our adapter class will have implemented target interface and it will have our Adaptee Class(or Interface) inside of it's body as member(composition, has a relation between adapter adaptee). And, adapter will override the interface implemented method using its adaptee provided methods. So, that is the general idea, lets see details in the example. 

Example : Let's consider a office . An office has many employee, and they are all full time. And, now company want expand its business to different area and will hire Remote employee who will be working as freelancer. So, our manager will should get those freelances accessible like as full time employee. And, we need an adapter to work for that. So, without the adapter and adaptee the system contains .
1. Employee Interface
2. Full time Employee applies all restrictions(methods) implemented from Employee
3. Client that uses a full time employee using employee interface.

And , for the newly added freelancers , we need to have
1. Freelance Employee who do not know about the system but do similar work like as employee(actually do not know the targeted interface)
2. Freelance Adapter class who knows the interface and represent an freelancer to client just like as full time employee..
So, finally client will use freelance adapter class and freelancer work together feel like as employee.

Let's see the code,here is our target interface IEmployee.
public interface IEmployee {

    public void attenOffice();

    public void joinMeeting();

    public void getDailyReport();

}
And, a system exist Class, FullTimeEmployee.


public class FullTimeEmployee implements IEmployee {

    private String name;

    public String getName() {

        return name;

    }

    public FullTimeEmployee(String aName){

        name=aName;

    }    

    public void attenOffice() {

        System.out.println(name+" is in office now");    

    }

    public void joinMeeting() {

        System.out.println(name+" is joining today's meeting");            

    }

    public void getDailyReport() {

        System.out.println(name+" is providing reports for today");    

    }

}


And, newly coming Freelancer (adaptee class)


public class Freelancer {

    private String name; 

    public String getName() {

        return name;

    }

    public void startWork(){

        System.out.println(name+" has started work remotely");    

    }

    public void remoteConversation(){

        System.out.print("\n"+name + " has started remote conversation");

    }

    public void getReport(String aDate){

        System.out.println(name+" is providing reports for "+aDate);

    }

    public Freelancer(String aName){

        name=aName;

    }

}


So, We need FreelanceAdapter class who implements IEmployee.

public class FreelancerAdapter implements IEmployee {

    private Freelancer freelancer = null;

    public FreelancerAdapter(Freelancer aFreelancer){

        freelancer=aFreelancer;

    }

    public void attenOffice() {

        System.out.println(freelancer.getName()+"'s has come to office, his Status : "); 

        freelancer.startWork();

    }

    public void joinMeeting() {

        freelancer.remoteConversation();

        System.out.print(" for meeting");        

    }

    public void getDailyReport() {

        DateFormat format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

        Date aDate = new Date();

        freelancer.getReport(format.format(aDate));

    }

}

And our client who calls the the adapter along with adaptee by IEmployee referrence.

public class Program {

    public static void main(String[] args) {

        IEmployee aExsistEmployee = new FullTimeEmployee("Mr. David");

        Freelancer aFreelancer = new Freelancer("Shantonu Sarker");

        IEmployee adapter = new FreelancerAdapter(aFreelancer);

        

       System.out.println("\n"+"This is sytem exist full time employee");

        aExsistEmployee.attenOffice();

        aExsistEmployee.joinMeeting();

        aExsistEmployee.getDailyReport();

        

        System.out.println("\n"+"This is new freelancer");

        aFreelancer.startWork();

        aFreelancer.remoteConversation();

        

        System.out.println("\n"+"This is freelancer and frelancerAdapter");

        adapter.attenOffice();

        adapter.getDailyReport();

        adapter.joinMeeting();    

    }

}


Java Example :
1. To keep simple, I have kept the adaptee as Class, but it can be interface. So, in that case, the interface implemented classes will be real adaptee.
2. I have use extra command print to have clear understanding on how it works.

C# Example :
1. I have change some method names as it works little differently from Java. 

Uses :
1. When we want to make a system compatible with another system.
2. Exist system enhancement.
3. Better refactoring and isolation.
4. Some times Two-Way adapters can make system very easy to handle.


Thanks...:)

2 comments: