-->

11/12/2011

Structural Pattern - Adapter Pattern - Object Adapter Pattern



I am a big time fan of Animation movies and cartoons.
I love cartoons like Calvin & Hobbes, Tom & Jerry; Animations like Shrek, Kung Fu Panda (Poo).
So, lets see how these characters will teach us Adapter pattern. :)

Adapter Pattern : This is one of the Structural patterns which will be widely used while dealing with legacy code. Let me clarify this first.
If i have a situation like:
1. My application is a an existing one and my Business logic was already getting used by other apps as well.
2. There are few other business components which were in market and getting used by many other apps.
3. Now, i got a request to accommodate these business components in my app.
4. But i cannot ask them to change their component to suite my application's interface.
5. I cannot keep on changing my applications logic, as i am not sure how many other business components will join my application.

In this kind of scenarios, Adapter Pattern will play a crucial role.

Lets see basic definition of it provided widely on many famous sites and blogs.

Participants

    The classes and/or objects participating in this pattern are:
  • Target 
    • defines the domain-specific interface that Client uses.
  • Adapter 
    • adapts the interface Adaptee to the Target interface.
  • Adaptee 
    • defines an existing interface that needs adapting.
  • Client   
    • collaborates with objects conforming to the Target interface.
Trying Hard ? Its easy to understand, but hard to interpret. I didn't able to do in first look either.

Lets go step by step as we always do.


Step 1: I want a project for animating my favorite cartoons. So i created one for Calvin.
For ease of development and understanding, i created a console application.
Interface "ICharacter.cs"
namespace AdapterSample
{
    public interface ICharacter
    {
        void AnimateCharacter();
    }    
}
Class "Calvin.cs"
namespace AdapterSample
{
    public class Calvin : ICharacter
    {
        public void AnimateCharacter()
        {
            Console.WriteLine("-------------------------------------------");
            Console.WriteLine("Animating Calvin's Head");
            Console.WriteLine("Animating Calvin's Body");
            Console.WriteLine("Animating Calvin's Legs");
            Console.WriteLine("Here we have animated figure of Calvin");
            Console.WriteLine("-------------------------------------------");
        }
    }
}
Step 2: I am done with business logic. Now i created Front end code,. i.e., in program.cs
namespace AdapterSample
{
    class Program
    {
        static void Main(string[] args)
        {
            ICharacter calvin = new Calvin();
            calvin.AnimateCharacter();
           
            Console.ReadKey();
        }
    }
}
Output:
Awesome. Isn't it.

Step 3: Now, i got a new request saying, there is an existing component or class which was written for animated character Shrek. I have to integrate it into my application.
namespace AdapterSample
{
    public class Shrek
    {
        public void AnimateShrek()
        {
            Console.WriteLine("-------------------------------------------");
            Console.WriteLine("Animating Shrek's Head");
            Console.WriteLine("Animating Shrek's Body");
            Console.WriteLine("Animating Shrek's Legs");
            Console.WriteLine("Here we have animated figure of Shrek");
            Console.WriteLine("-------------------------------------------");
        }
    }
}
If you closely observe the methods in Interface, Calvin class and Shrek class, the method name is different in Shrek. Now i cannot ask them to change method name in Shrek class. I cannot keep on adding new method signature in my interface.

Step 4: Its time for an adapter. I created a new Adapter called "ShrekAdapter".
namespace AdapterSample
{
    public class ShrekAdapter:Shrek , ICharacter
    {
        public void AnimateCharacter()
        {
            AnimateShrek();
        }
    }
}
Observe this clearly. This class is inheriting Shrek and implementing Interface (ICharacter). So, i am not gonna change any code in either of them. All i did here is implement interface and defined AnimateCharacter() method and associate it with Shrek's AnimateShrek() method.

If your code has a concrete class it should have a virtual method, so that it can be overridden in child class.

Now if you say my application have neither a virtual methods nor an interface. That means your application is closed for extension, which is completely against to "Open Close Design Principle".
"Software entities like classes, modules and functions should be open for extension but closed for modifications."

Step 5: Change the front end code to see how the new adapter works.
namespace AdapterSample
{
    class Program
    {
        static void Main(string[] args)
        {
            //Calvin
            ICharacter calvin = new Calvin();
            calvin.AnimateCharacter();
            
            //Shrek
            ICharacter shrek = new ShrekAdapter();
            shrek.AnimateCharacter();

            Console.ReadKey();
        }
    }
}
Output:
 Great. No modifications in my app's interface and Shrek's class.

Step 6: Now, i got another request to add a existing component for Kung Fu Panda (Poo).
namespace AdapterSample
{
    public class Poo
    {
        public void AnimatePoo()
        {
            Console.WriteLine("-------------------------------------------");
            Console.WriteLine("Animating Poo's Head");
            Console.WriteLine("Animating Poo's Body");
            Console.WriteLine("Animating Poo's Legs");
            Console.WriteLine("Here we have animated figure of Poo");
            Console.WriteLine("-------------------------------------------");
        }
    }
}
Step 7: If you try to inherit "Poo" class from "ShrekAdapter", that wont work at all. Reason being "Multiple Inheritance is not possible in C#". So we need to create a new adapter for Poo as well.
namespace AdapterSample
{
    public class PooAdapter:Poo , ICharacter
    {
        public void AnimateCharacter()
        {
            AnimatePoo();
        }
    }
}
Step 8: My front end code changed like this:
namespace AdapterSample
{
    class Program
    {
        static void Main(string[] args)
        {
            //Calvin
            ICharacter calvin = new Calvin();
            calvin.AnimateCharacter();
            
            //Shrek
            ICharacter shrek = new ShrekAdapter();
            shrek.AnimateCharacter();

            //Poo
            ICharacter poo = new PooAdapter();
            poo.AnimateCharacter();

            Console.ReadKey();
        }
    }
}
Step 9: We are done, but this code is not looking good. Its not centralized. So lets create a static class AdapterFactory which will take care of instantiating all the adapters.
namespace AdapterSample
{
    public static class AdapterFactory
    {
        public static ICharacter GetInstance(string strCharacter)
        {
            switch (strCharacter)
            {
                case "SHREK":
                    return new ShrekAdapter();
                case "POO":
                    return new PooAdapter();
                default:
                    throw new Exception("Unadapted Character");
            }
        }
    }
}
Step 10: Look how good our front end code will look like now.
namespace AdapterSample
{
    class Program
    {
        static void Main(string[] args)
        {
            //Calvin
            ICharacter calvin = new Calvin();
            calvin.AnimateCharacter();
            
            //Shrek
            ICharacter shrek = AdapterFactory.GetInstance("SHREK");
            shrek.AnimateCharacter();

            //Poo
            ICharacter poo = AdapterFactory.GetInstance("POO");
            poo.AnimateCharacter();

            Console.ReadKey();
        }
    }
}
Output:

Finally lets map the roles once again which were described above immediately after UML diagram.
Adaptee - Sherk and Poo classes
Target - Interface ICharacter
Adapter - ShrekAdapter and PooAdapter

Now look back at UML and recollect how we included the Adaptee component with out affecting Target component.

With this we are done with a simple example for Class Adapter pattern. In our next post we will look into Object Adapter pattern.
Code:
Click Here
Is it helpful for you? Kindly let me know your comments / Questions

1 comment:

  1. Great! you illustrated it very well.

    --Mahesh

    ReplyDelete