Recent Implementation of Adapter Design Pattern
Recently, I successfully implemented the Adapter Pattern to seamlessly integrate Google Map's Direction service into our current .NET project.
At its core, the Adapter Pattern acts as a bridge, closing the gap between two different interfaces. In our system, we utilize a versatile class named AddressInfo to handle various address locations. This class serves as a generic container for location details. The class looks like this
public class AddressInfo
{
public double Lat { get; set; }
public double Lng { get; set; }
public string Address { get; set; }
public string Country { get; set; }
public string State { get; set; }
public string CantonKey { get; set; }
public string City { get; set; }
public string Street { get; set; }
public string PoBox { get; set; }
public string Street_Number { get; set; }
public string House_Number { get; set; }
public string Postal_Code { get; set; }
public string Country_Code { get; set; }
...
...
}
When calculating the distance between two locations using Google Map Direction service, it necessitates the use of coordinates, comprising the longitude and latitude of each location. Though it can also return distances if the location is given in the text, using coordinates seems more intuitive.
To streamline this process, I designed an adapter class that exposes a straightforward method for obtaining the distance between two locations. Embracing polymorphism, I introduced two overloaded methods—one accepting source and destination locations with latitude and longitude like the following,
public class LocationPoint
{
public double lat { get; set; }
public double lng { get; set; }
}
and another accommodating our system's generic format, AddressInfo.
Recommended by LinkedIn
This enhancement allows us to use the methods seamlessly within our system. If both locations are in the system's generic form, there's no need to parse latitude and longitude, eliminating the overhead of creating a compatible object. Simultaneously, when an instance of the generic AddressInfo is unavailable, the alternative method allows for a straightforward and clear input format.
Additionally, the adapter class incorporates various configurations mapped to the parameters of the REST call made to the Google Map Direction service. This ensures that clients can easily configure settings as needed.
A glimpse of one method
public async Task<double> GetDistanceBetweenLocationsAsync(AddressInfo source, AddressInfo destination)
{
if (source == null || destination == null) return 0;
var sourcePoint = new LocationPoint
{
lat = source.Lat,
lng = source.Lng,
};
var destinationPoint = new LocationPoint
{
lat = source.Lat,
lng = source.Lng,
};
var uri = GetRouteServiceUrl(sourcePoint, destinationPoint);
var response = await _restCommunication.GetRequestAsync(uri);
var mapDirectionResponse = JsonConvert.DeserializeObject<MapDirectionResponse>(response);
double minDistanceInMeter = double.MaxValue;
if (mapDirectionResponse!=null && mapDirectionResponse.status == "OK" && mapDirectionResponse.routes.Count > 0)
{
foreach (var route in mapDirectionResponse.routes)
{
double totalDistanceInCurrentRoute = route.legs.Sum(leg => leg?.distance?.value ?? 0);
minDistanceInMeter = Math.Min(minDistanceInMeter, totalDistanceInCurrentRoute);
}
}
if (minDistanceInMeter == double.MaxValue) minDistanceInMeter = 0;
return minDistanceInMeter;
}
To sum up, a design pattern isn't an algorithm or technology; it's more akin to an obvious and intuitive solution. More often than not, it feels like, this is what everyone probably does or should do. After implementing various design patterns such as Strategy, Factory, and Facade across different codebases, I've consistently thought, 'Why the need for such fancy names? This is exactly what I felt towards terms like 'Sliding Window' or 'Two Pointers.'
But then again, I realized that our brains need a quick mental map for categorizing problems and finding efficient solutions. If we do not have a name for a certain thing, our brains cannot figure that out easily. In the case of my solution using an adapter pattern, it could have been the fact that, I would probably overlook the need for creating two polymorphic methods. After all, it won't take much time to create the instance of a very simple class with only two fields. but the properties underneath such a class made me think of the term Adapter because I knew that there is a design pattern with the same name.
HAPPY CODING!