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.

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!

To view or add a comment, sign in

More articles by Rezaul Karim

  • The Hidden Danger of Shared State in Angular Unit Tests

    Recently, while working on a legacy Angular project, I encountered an interesting — and admittedly a little frustrating…

  • Why You Should Never Write Business Logic Inside a Component's Constructor Function (Angular)

    Many developers would say that making the creation of any object costly is a bad practice. When there are many tasks to…

  • Atomicity in Database

    Atom শব্দের অর্থ পরমাণু। এমন নামকরণের কারণ নিশ্চয় এই যে, একসময় মনে করা হতো এটাই পদার্থের ক্ষুদ্রতম কণা, যাকে আর ভাঙ্গা…

    3 Comments
  • 5 Common Mistakes I Have Seen in Writing REST API

    Including the method name in the URI.Example : Here, using a method name like getUser is just unnecessary.

    2 Comments

Insights from the community

Others also viewed

Explore topics