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.
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.
Step 2: I am done with business logic. Now i created Front end code,. i.e., in program.csInterface "ICharacter.cs" namespace AdapterSample { public interface ICharacter { voidAnimateCharacter(); } }Class "Calvin.cs" namespace AdapterSample { public class Calvin : ICharacter { public voidAnimateCharacter() { 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("-------------------------------------------"); } } }
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 voidIf 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.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("-------------------------------------------"); } } }
Step 4: Its time for an adapter. I created a new Adapter called "ShrekAdapter".
namespace AdapterSample { public class ShrekAdapter: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.Shrek , ICharacter { public voidAnimateCharacter() {AnimateShrek(); } } }
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(); //ShrekOutput:ICharacter shrek = new ShrekAdapter(); shrek.AnimateCharacter(); Console.ReadKey(); } } }
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 voidStep 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.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("-------------------------------------------"); } } }
namespace AdapterSample { public class PooAdapter:Step 8: My front end code changed like this:Poo , ICharacter { public voidAnimateCharacter() {AnimatePoo(); } } }
namespace AdapterSample { class Program { static void Main(string[] args) { //Calvin ICharacter calvin = new Calvin(); calvin.AnimateCharacter(); //ShrekStep 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.ICharacter shrek = new ShrekAdapter(); shrek.AnimateCharacter(); //PooICharacter poo = new PooAdapter(); poo.AnimateCharacter(); Console.ReadKey(); } } }
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 =Output:AdapterFactory.GetInstance("SHREK"); shrek.AnimateCharacter(); //Poo ICharacter poo =AdapterFactory.GetInstance("POO"); poo.AnimateCharacter(); Console.ReadKey(); } } }
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
Great! you illustrated it very well.
ReplyDelete--Mahesh