Design Pattern: Adapter Pattern. How I use a simple pattern to write flexible, maintainable, and high-performance code.

With adapter pattern, I wrote a flexible, maintainable, easy to debug code and cut down on regression test.

1 0
Read Time:4 Minute, 33 Second

I need to create an extraction batch job today at work. The goal is to extract an existing report in my application and send it to another system periodically for analytical purposes. Some fields in the report does not exists in the database, they are computed runtime by backend server. Additionally, not all records in database are valid, selection rules must be applied to filter the records when generating the report.

I can use the existing report class and make use the method to generate report. But the problem? The method returns Output Stream. I can’t use the method as is. I need to extend the extraction report with some additional fields and I need to compute it based on some fields.

This is a common problem in programming. You want to make use of existing methods, but you don’t want to change it and increase required effort on regression test, and worse, break the method. Especially if it’s not protected by automated test.

This is a good scenario to make use of adapter pattern.

Adapter Pattern

This pattern is easy to understand. Think of adapters in real life. If you have a US phone charger, but the wall plug is UK, what do you do? You buy a UK universal adapter plug. The adapter converts from one interface to another. This example is analogous to Object Oriented adapter. In practice, we have a class (client) that expects some kind of object, and an adapter converts the interface of the service class to the object that the client can accept.

Benefit of adapter pattern:

  1. The code is reusable and flexible. The same code can now be extended to serve multiple client.
  2. Clean and readable code. The conversion logic between 2 different interfaces are encapsulated in a class. Resulting in a more readable client class.

Implementation Structure

There are 2 ways to implement adapter pattern:

  1. Object adapter
  2. Class adapter

Object adapter implementation uses the object composition principle: the adapter implements the interface of one object and wraps the other one. It can be implemented in all popular programming languages.

Class adapter implementation uses inheritance: the adapter inherits interfaces from both objects at the same time. Note that this approach can only be implemented in programming languages that support multiple inheritance, such as C++.

I will discuss about Object adapter implementation because I use Java and it doesn’t support multiple inheritance.

Object Adapter Implementation

Class diagram above is how I implement my solution.

CSVReportService class is the existing service that generates the report file.

ExtractionClient is the new service I am writing that extracts the report from my app and sends it to another source. It requires some changes to existing report to meet security and business requirements.

I create 3 new class: ReportServiceInterface, ReportServiceImpl, and Record. Record is just the POJO which is the result from CSVReportService that ReportServiceInterface will return back to Extraction Client. ReportServiceImpl is where I store an instance of CSVReportService and perform data transformation.

Whenever ExtractionClient calls ReportServiceInterface.generate(..) method, ReportServiceImpl will pass the invocation to CSVReportService.generate(..). It will then store the result in a StringBuffer. Then it will read the StringBuffer line by line and convert it to Record object. The Record object makes it possible for ExtractionClient to do further enrichment on the data before sending it out. With this simple approach, I have extended CSVReportService functionality further.

I won’t go in-depth into how I convert from String to Object. If you’re interested, I can let you know that I use Reflection to avoid hard coding and make it make the conversion configurable. I have to convert over 10 schemas to a single object. Comment below if you’re interested!

Benefit of the following approach:

  1. Code is flexible. I can swap the ReportServiceImpl to another if I need to change the implementation in the future.
  2. Code is not complex and easy to debug. We have achieved the Single Responsibility principle with this solution. ExtractionClient class will be simpler to debug with less code, and if there’s a problem with the conversion, it will be obvious the problem lies within ReportServiceImpl class.
  3. Achieved other SOLID principles:
    1. Open-closed principle. We did not modify existing class: CSVReportService, which would have cost us more time for regression test and risk breaking existing functionalities.
    2. Interface segregation principle. We used ReportServiceInterface and hide the actual implementation class away from ExtractionClient. It will be easy for us to make changes to the conversion method without affecting ExtractionClient.

Disadvantages:

  1. CPU overhead on string manipulation and conversion of string to object may fail.

Conclusion

You may ask me “Why not just create a new method in CSVReportService?”. It’s because the existing class has many complex business logic to compute certain attributes on runtime. I skipped the implementation complexities and water them down to highlight the importance of incorporating design patterns in code solutions.

With this simple approach, I wrote a flexible, maintainable, easy to debug code and cut down on regression test. All of this eventually translates to less time spent on fixing bugs, and do more enhancements to help our users with their tasks and value add to their work.

Read more

We have discussed a specific implementation here, to learn more design pattern, and SOLID principles. I recommend the following links:

  1. Design Pattern https://refactoring.guru/design-patterns/what-is-pattern
  2. SOLID Principles https://www.digitalocean.com/community/conceptual_articles/s-o-l-i-d-the-first-five-principles-of-object-oriented-design
Happy
Happy
0 %
Sad
Sad
0 %
Excited
Excited
0 %
Sleepy
Sleepy
0 %
Angry
Angry
0 %
Surprise
Surprise
0 %
docker headline Previous post Docker – What is it and why is it so good?
Next post What you need to know about Big Data

Average Rating

5 Star
0%
4 Star
0%
3 Star
0%
2 Star
0%
1 Star
0%

Leave a Reply

Your email address will not be published. Required fields are marked *