Adapter design pattern - Structural
Pradip Shinde
Software Architect | Transformation | Scalable Apps | Microservices | .Net 6
?
?Definition -
Converts the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces. Adapter is a structural design pattern that allows objects with incompatible interfaces to collaborate.
Problem statement –
Displaying charts/reports in stock market monitoring application.
The application downloads the stock data from multiple sources in XML format and then displays nice-looking charts and diagrams for the user. At some point, you decide to improve the app by integrating a smart 3rd-party analytics library. But there’s a catch: the analytics library only works with data in JSON format.
You could change the JSON Analytics library to work with XML. However, this might break another apps that relies on the library. And worse, you might not have access to the library’s source code in the first place, making this approach impossible.
Solution -
Simply go ahead in the current application source code(which uses xml data) and do modification in the same method to convert into JSON. PLEASE! PLEASE!! PLEASE!!! Do not change the existing class which will violate Single Responsibility Principle.
What is the solution then? Lets create an adapter. This is a special object that converts the interface of one object so that another object can understand it.
An adapter wraps one of the objects to hide the complexity of conversion happening behind the scenes. The wrapped object isn’t even aware of the adapter. For example, you can wrap an object that operates in meters and kilometers with an adapter that converts all of the data to imperial units such as feet and miles.
Adapters can not only convert data into various formats but can also help objects with different interfaces collaborate. Here’s how it works:
- The adapter gets an interface, compatible with one of the existing objects.
- Using this interface, the existing object can safely call the adapter’s methods.
- Upon receiving a call, the adapter passes the request to the second object, but in a format and order that the second object expects.
Sometimes it’s even possible to create a two-way adapter that can convert the calls in both directions.
Code Snippet -
// The Target defines the domain-specific interface used by the client code. public interface ITarget { string GetData(); } // The StockData (Adaptee) contains some logic to get the data from different sources in xml format. class StockData { /// <summary> /// Returns XML data /// </summary> /// <returns></returns> public string GeData() { return "XML Data"; } } // The JSONFormattedData (Adapter) makes the Adaptee's interface //compatible with the Target's interface. class JSONFormattedData : ITarget { private readonly StockData _adaptee; public JSONFormattedData(StockData adaptee) { this._adaptee = adaptee; } public string GetData() { var xml = _adaptee.GeData(); XmlDocument doc = new XmlDocument(); doc.LoadXml(xml); return JsonConvert.SerializeXmlNode(doc); } } class Program { static void Main(string[] args) { StockData adaptee = new StockData(); ITarget target = new JSONFormattedData(adaptee); // TODO - use converted json data using third party analytics library } }
Benefits –
- Single Responsibility Principle - You can separate the interface or data conversion code from the primary business logic of the program.
- Open/Closed Principle - You can introduce new types of adapters into the program without breaking the existing client code, as long as they work with the adapters through the client interface.
Relationships with other patterns –
Bridge is usually designed up-front, letting you develop parts of an application independently of each other. On the other hand, Adapter is commonly used with an existing app to make some otherwise-incompatible classes work together nicely.
Adapter changes the interface of an existing object, while Decorator enhances an object without changing its interface. In addition, Decorator supports recursive composition, which isn’t possible when you use Adapter.
Adapter provides a different interface to the wrapped object, Proxy provides it with the same interface, and Decorator provides it with an enhanced interface.
Facade defines a new interface for existing objects, whereas Adapter tries to make the existing interface usable. Adapter usually wraps just one object, while Facade works with an entire subsystem of objects.
Bridge, State, Strategy (and to some degree Adapter) have very similar structures. Indeed, all of these patterns are based on composition, which is delegating work to other objects. However, they all solve different problems. A pattern isn’t just a recipe for structuring your code in a specific way. It can also communicate to other developers the problem the pattern solves.
Technical Lead | Expert in Telecommunications, E-commerce, ERP Solutions & Healthcare Systems | 18 Years of Experience
3 年Great article
Executive at PlusOne Marketing Solutions
3 年What are Design Patterns in Java? https://www.decipherzone.com/blog-detail/design-patterns-java Design patterns are proven solutions for solving certain problems faced during the development of the software. It represents best practices used by software developers. Design patterns have been obtained by trial and error that software developers did over an abundant period.
...
4 年Nice explanation Pradip Shinde!
Software Engineer
4 年Wonderful ! Such a nice explanation.
Dot Net Full Stack Developer | Microsoft Azure (App Service [PaaS], SQL Database, Functions, Scaling) | Collaboration and communication | Agile Methodology
4 年Nice explanation! Good read