Sunday, August 5, 2007

Adapter Pattern : adapt your interfaces

hi,

oen of the problems which i faced while developing some component was with arraylist. This arraylist is present in System.Collections namespace. teh problem which i faced was that, i had created an arraylist to hold a particular interface (say for my game , it would be ICar interface). now i add objects of type car here into the arraylist, and while retrieving objects from the arraylist, i type cats it to ICar. it works fine. but a new requirement arises and we have to keep track of a new interface IPlane in the arraylist. so, while retrieving , i will have to typecast the object to ICar and if an exception is thrown, catch it and typecast the same object to IPlane. this is not proper code, why? because tomorrow, if i want to add a new interface IShip to Arraylist, ihaev to catch another exception and then typecast it to IShip? exactly, then my code will be filled with only try catch block in a nested format. But wher did i go wrong in the design? i had a n interface, i did the best possible design. yes, until here, i have done the best possible design.but where i went wrong was directly adding the object which implement IPlane interface to the arraylist. This caused confusion between ICar and IPlane in the arraylist while retrieving. yes i do have a solution for this problem. we have to wrap the Plane Object in someother class. Also this wrapper for IPlane whould conform to ICar interface...confusing? in simple terms, we introduce a new class which composes of IPlane and implements ICar. This is the Adapter Class. this Adapts IPlane to conform to ICar.


See the code below :


using System;
using
System.Collections.Generic;
using
System.Text;
namespace
FactoryPattern
{
public interface ICar
{
//some properties here
}
class Audi : ICar
{
public Audi()
{
}
//implemnt the interface here
}
class Benz : ICar
{
public Benz()
{
}
//implemnt the interface here
}

public class CarFactory
{
public CarFactory()
{
}

}

}

I have an arraylist wher in i add CarObjects,

ArrayList transportVehicles = new ArrayList();
transportVehicles.Add(
(ICar)new Car());
for (int i = 0; i < transportVehicles.Count; i++)
{
ICar car = (ICar)transportVehicles[i];
car.Move();
}

Now i introduce a new mode of tranport- a plane (it flies instead of moving on land).


ArrayList transportVehicles = new ArrayList();
transportVehicles.Add(
(ICar)new Car());
transportVehicles.Add((
IPlane)new Plane());
for (int i = 0; i < transportVehicles.Count; i++)
{
ICar car = (ICar)transportVehicles[i];
car.Move();
}

Then iwll get an exception, coz the second object in the arraylist is of type IPlane and it cannot be typecasted to ICar.

So now i introduce another class called the Adapter which Adapts the Iplane interface to ICar interface

public class PlaneAdapter : ICar
{
IPlane plane;
public PlaneAdapter(IPlane planeobject)
{
plane = planeobject;
}
public void Move()
{
plane.Fly();
}

}

And then change the method of invoking to

ArrayList transportVehicles = new ArrayList();
transportVehicles.Add((
ICar)new Car());
transportVehicles.Add((
ICar)new PlaneAdapter((IPlane)new Plane())); // notice the change here
//Plane adapter implements ICar, so we can type cats PlaneAdapter to ICar
for (int i = 0; i < transportVehicles.Count; i++)
{
ICar car = (ICar)transportVehicles[i];
car.Move();
}

Now there will be no exception and also teh output will be

car is moving

The plane is flying



All I did was to introduce another class which implemented ICar and composed IPlane. This worked like magic for me!! hope this will help you too.

Happy Coding!!!


No comments: