adapter-Any real example of Adapter Pattern

OopDesign PatternsAdapterSoftware Design

Oop Problem Overview


I want to demonstrate use of Adapter Pattern to my team. I've read many books and articles online. Everyone is citing an example which are useful to understand the concept (Shape, Memory Card, Electronic Adapter etc.), but there is no real case study.

Can you please share any case study of Adapter Pattern?

p.s. I tried searching existing questions on stackoverflow, but did not find the answer so posting it as a new question. If you know there's already an answer for this, then please redirect.

Oop Solutions


Solution 1 - Oop

Many examples of Adapter are trivial or unrealistic (Rectangle vs. LegacyRectangle, Ratchet vs. Socket, SquarePeg vs RoundPeg, Duck vs. Turkey). Worse, many don't show multiple Adapters for different Adaptees (someone cited Java's Arrays.asList as an example of the adapter pattern). Adapting an interface of only one class to work with another seems a weak example of the GoF Adapter pattern. This pattern uses inheritance and polymorphism, so one would expect a good example to show multiple implementations of adapters for different adaptees.

The best example I found is in Chapter 26 of Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development (3rd Edition). The following images are from the instructor material provided on an FTP site for the book.

The first one shows how an application can use multiple implementations (adaptees) that are functionally similar (e.g., tax calculators, accounting modules, credit authorization services, etc.) but have different APIs. We want to avoid hard-coding our domain-layer code to handle the different possible ways to calculate tax, post sales, authorize credit card requests, etc. Those are all external modules that might vary, and for which we can't modify the code. The adapter allows us to do the hard-coding in the adapter, whereas our domain-layer code always uses the same interface (the IWhateverAdapter interface).

Fig. 26.1

We don't see in the above figure the actual adaptees. However, the following figure shows how a polymorphic call to postSale(...) in the IAccountingAdapter interface is made, which results in a posting of the sale via SOAP to an SAP system.

Fig. 26.2

Solution 2 - Oop

How to turn a french person into a normal person...

 public interface IPerson
    {
        string Name { get; set; }
    }

    public interface IFrenchPerson
    {
        string Nom { get; set; }
    }

    public class Person : IPerson
    {
        public string Name { get; set; }
    }

    public class FrenchPerson : IFrenchPerson
    {
        public string Nom { get; set; }
    }

    // that is a service that we want to use with our French person
    // we cannot or don't want to change the service contract
    // therefore we need 'l'Adaptateur'
    public class PersonService
    {
        public void PrintName(IPerson person)
        {
            Debug.Write(person.Name);
        }
    }

    public class FrenchPersonAdapter : IPerson
    {
        private readonly IFrenchPerson frenchPerson;

        public FrenchPersonAdapter(IFrenchPerson frenchPerson)
        {
            this.frenchPerson = frenchPerson;
        }

        public string Name 
        {
            get { return frenchPerson.Nom; }
            set { frenchPerson.Nom = value; }
        }
    } 

Example

    var service = new PersonService();
    var person = new Person();
    var frenchPerson = new FrenchPerson();

    service.PrintName(person);
    service.PrintName(new FrenchPersonAdapter(frenchPerson));

Solution 3 - Oop

Convert an Interface into another Interface. >Any real example of Adapter Pattern

In order to connect power, we have different interfaces all over the world. Using Adapter we can connect easily like wise.

enter image description here

Solution 4 - Oop

Here is an example that simulates converting analog data to digit data.

It provides an adapter that converts float digit data to binary data, it's probably not useful in real world, it just helps to explain the concept of adapter pattern.


Code

AnalogSignal.java

package eric.designpattern.adapter;

public interface AnalogSignal {
	float[] getAnalog();

	void setAnalog(float[] analogData);

	void printAnalog();
}

DigitSignal.java

package eric.designpattern.adapter;

public interface DigitSignal {
	byte[] getDigit();

	void setDigit(byte[] digitData);

	void printDigit();
}

FloatAnalogSignal.java

package eric.designpattern.adapter;

import java.util.Arrays;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FloatAnalogSignal implements AnalogSignal {
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	private float[] data;

	public FloatAnalogSignal(float[] data) {
		this.data = data;
	}

	@Override
	public float[] getAnalog() {
		return data;
	}

	@Override
	public void setAnalog(float[] analogData) {
		this.data = analogData;
	}

	@Override
	public void printAnalog() {
		logger.info("{}", Arrays.toString(getAnalog()));
	}
}

BinDigitSignal.java

package eric.designpattern.adapter;

import java.util.Arrays;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class BinDigitSignal implements DigitSignal {
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	private byte[] data;

	public BinDigitSignal(byte[] data) {
		this.data = data;
	}

	@Override
	public byte[] getDigit() {
		return data;
	}

	@Override
	public void setDigit(byte[] digitData) {
		this.data = digitData;
	}

	@Override
	public void printDigit() {
		logger.info("{}", Arrays.toString(getDigit()));
	}
}

AnalogToDigitAdapter.java

package eric.designpattern.adapter;

import java.util.Arrays;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <p>
 * Adapter - convert analog data to digit data.
 * </p>
 * 
 * @author eric
 * @date Mar 8, 2016 1:07:00 PM
 */
public class AnalogToDigitAdapter implements DigitSignal {
	public static final float DEFAULT_THRESHOLD_FLOAT_TO_BIN = 1.0f; // default threshold,
	private Logger logger = LoggerFactory.getLogger(this.getClass());

	private AnalogSignal analogSignal;
	private byte[] digitData;
	private float threshold;
	private boolean cached;

	public AnalogToDigitAdapter(AnalogSignal analogSignal) {
		this(analogSignal, DEFAULT_THRESHOLD_FLOAT_TO_BIN);
	}

	public AnalogToDigitAdapter(AnalogSignal analogSignal, float threshold) {
		this.analogSignal = analogSignal;
		this.threshold = threshold;
		this.cached = false;
	}

	@Override
	public synchronized byte[] getDigit() {
		if (!cached) {
			float[] analogData = analogSignal.getAnalog();
			int len = analogData.length;
			digitData = new byte[len];

			for (int i = 0; i < len; i++) {
				digitData[i] = floatToByte(analogData[i]);
			}
		}

		return digitData;
	}

	// not supported, should set the inner analog data instead,
	@Override
	public void setDigit(byte[] digitData) {
		throw new UnsupportedOperationException();
	}

	public synchronized void setAnalogData(float[] analogData) {
		invalidCache();
		this.analogSignal.setAnalog(analogData);
	}

	public synchronized void invalidCache() {
		cached = false;
		digitData = null;
	}

	@Override
	public void printDigit() {
		logger.info("{}", Arrays.toString(getDigit()));
	}

	// float -> byte convert,
	private byte floatToByte(float f) {
		return (byte) (f >= threshold ? 1 : 0);
	}
}

Code - Test case

AdapterTest.java

package eric.designpattern.adapter.test;

import java.util.Arrays;

import junit.framework.TestCase;

import org.junit.Test;

import eric.designpattern.adapter.AnalogSignal;
import eric.designpattern.adapter.AnalogToDigitAdapter;
import eric.designpattern.adapter.BinDigitSignal;
import eric.designpattern.adapter.DigitSignal;
import eric.designpattern.adapter.FloatAnalogSignal;

public class AdapterTest extends TestCase {
	private float[] analogData = { 0.2f, 1.4f, 3.12f, 0.9f };
	private byte[] binData = { 0, 1, 1, 0 };
	private float[] analogData2 = { 1.2f, 1.4f, 0.12f, 0.9f };

	@Test
	public void testAdapter() {
		AnalogSignal analogSignal = new FloatAnalogSignal(analogData);
		analogSignal.printAnalog();

		DigitSignal digitSignal = new BinDigitSignal(binData);
		digitSignal.printDigit();

		// adapter
		AnalogToDigitAdapter adAdapter = new AnalogToDigitAdapter(analogSignal);
		adAdapter.printDigit();
		assertTrue(Arrays.equals(digitSignal.getDigit(), adAdapter.getDigit()));

		adAdapter.setAnalogData(analogData2);
		adAdapter.printDigit();
		assertFalse(Arrays.equals(digitSignal.getDigit(), adAdapter.getDigit()));
	}
}

Dependence - via maven

	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.8.2</version>
	</dependency>

	<dependency>
		<groupId>org.slf4j</groupId>
		<artifactId>slf4j-api</artifactId>
		<version>1.7.13</version>
	</dependency>
	<dependency>
		<groupId>org.slf4j</groupId>
		<artifactId>slf4j-log4j12</artifactId>
		<version>1.7.13</version>
	</dependency>
	<dependency>
		<groupId>log4j</groupId>
		<artifactId>log4j</artifactId>
		<version>1.2.16</version>
	</dependency>

How to test

Just run the unit test.

Solution 5 - Oop

> Adapter pattern works as a bridge between two incompatible interfaces. > This pattern involves a single class called adapter which is > responsible for communication between two independent or incompatible > interfaces.

Real-world examples might be a language translator or a mobile charger. More here in this youtube video:

Youtube - Adapter Design pattern: Introduction

Solution 6 - Oop

You can use the Adapter design pattern when you have to deal with different interfaces with similar behavior (which usually means classes with similar behavior but with different methods). An example of it would be a class to connect to a Samsung TV and another one to connect to a Sony TV. They will share common behavior like open menu, start playback, connect to a network and etc but each library will have a different implementation of it (with different method names and signatures). These different vendor specific implementations are called Adaptee in the UML diagrams.

So, in your code (called Client in the UML diagrams), instead of hard code the method calls of each vendor (or Adaptee), you could then create a generic interface (called Target in UML diagrams) to wrap these similar behaviors and work with only one type of object.

The Adapters will then implement the Target interface delegating its method calls to the Adaptees that are passed to the Adapters via constructor.

For you to realize this in Java code, I wrote a very simple project using exactly the same example mentioned above using adapters to deal with multiple smart TV interfaces. The code is small, well documented and self explanatory so dig on it to see how a real world implementation would look like.

Just download the code and import it to Eclipse (or your favorite IDE) as a Maven project. You can execute the code by running org.example.Main.java. Remember that the important thing here is to understand how classes and interfaces are assembled together to design the pattern. I also created some fake Adaptees in the package com.thirdparty.libs. Hope it helps!

https://github.com/Dannemann/java-design-patterns

Solution 7 - Oop

Adapter design patterns helps in converting interface of one class into interface of client expects.

Example: You have a service which returns weather (in celsius) by passing city name as a input value. Now, assume that your client wants to pass zipcode as input and expecting the temperature of the city in return. Here you need an adaptor to achieve this.

public interface IWetherFinder {
    public double getTemperature(String cityName);
}

class WeatherFinder implements IWetherFinder{
   @Override
   public double getTemperature(String cityName){
     return 40;
   }
}

interface IWeatherFinderClient
{
   public double getTemperature(String zipcode);
}  

public class WeatherAdapter implements IWeatherFinderClient {

	@Override
	public double getTemperature(String zipcode) {
		
		//method to get cityname by zipcode 
		String cityName = getCityName(zipcode);
		
		//invoke actual service
		IWetherFinder wetherFinder = new WeatherFinder();
		return wetherFinder.getTemperature(cityName);
	}
	
	private String getCityName(String zipCode) {
		return "Banaglore";
	}
}

Solution 8 - Oop

You can find a PHP implementation of the Adapter pattern used as a defense against injection attacks here:

http://www.php5dp.com/category/design-patterns/adapter-composition/

One of the interesting aspects of the Adapter pattern is that it comes in two flavors: A class adapter relying on multiple inheritance and an object adapter relying on composition. The above example relies on composition.

Solution 9 - Oop

One Real example is Qt-Dbus.

The qt-dbus has a utility to generate the adaptor and interface code from the xml file provided. Here are the steps to do so.

 1. Create the xml file - this xml file should have the interfaces 
that can be viewed by the qdbus-view in the system either on 
the system or session bus.
    
    2.With the utility - qdbusxml2cpp , you generate the interface adaptor code. 
This interface adaptor does the demarshalling of the data that is 
received from the client. After demarshalling, it invokes the 
user defined - custom methods ( we can say as adaptee).
    
    3. At the client side, we generate the interface from the xml file. 
This interface is invoked by the client. The interface does the 
marshalling of the data and invokes the adaptor interface. As told 
in the point number 2, the adaptor interface does the demarshalling 
and calls the adaptee - user defined methods.

You can see the complete example of Qt-Dbus over here -

http://www.tune2wizard.com/linux-qt-signals-and-slots-qt-d-bus/

Solution 10 - Oop

Use Adapter when you have an interface you cannot change, but which you need to use. See it as you're the new guy in an office and you can't make the gray-hairs follow your rules - you must adapt to theirs. Here is a real example from a real project I worked on sometime where the user interface is a given.

You have an application that read all the lines in a file into a List data structure and displayed them in a grid (let's call the underlying data store interface IDataStore). The user can navigate through these data by clicking the buttons "First page", "Previous page", "Next page", "Last Page". Everything works fine.

Now the application needs to be used with production logs which are too big to read into memory but the user still needs to navigate through it! One solution would be to implement a Cache that stores the first page, next, previous and last pages. What we want is when the user clicks "Next page", we return the page from the cache and update the cache; when they click last page, we return last page from cache. In the background we have a filestream doing all the magic. By so doing we only have four pages in memory as opposed to the entire file.

You can use an adapter to add this new cache feature to your application without the user noticing it. We extend the current IDataStore and call it CacheDataStore. If the file to load is big, we use CacheDataStore. When we make a request for First, Next, Previous and Last pages, the information is routed to our Cache.

And who knows, tomorrow the boss wants to start reading the files from a database table. All you do is still extend IDataStore to SQLDataStore as you did for Cache, setup the connection in the background. When they click Next page, you generate the necessary sql query to fetch the next couple hundred rows from the database.

Essentially, the original interface of the application did not change. We simply adapted modern and cool features to work it while preserving the legacy interface.

Solution 11 - Oop

@Justice o's example does not talk about adapter pattern clearly. Extending his answer - We have existing interface IDataStore that our consumer code uses and we cannot change it. Now we are asked to use a cool new class from XYZ library that does what we want to implement, but but but, we cannot change that class to extend our IDataStore, seen the problem already ? Creating a new class - ADAPTER, that implements interface our consumer code expects, i.e. IDataStore and by using class from the library whose features we need to have - ADAPTEE, as a member in our ADAPTER, we can achieve what we wanted to.

Solution 12 - Oop

As per “C# 3.0 Design Patterns” book by Judith Bishop, Apple used Adapter pattern to adapt Mac OS to work with Intel products (explained in Chapter # 4, excerpt here2)

Solution 13 - Oop

An example from Yii framework would be: Yii uses internally cache utilizing an interface ICache. https://www.yiiframework.com/doc/api/1.1/ICache

whose signature is like : -

abstract public boolean set(string $id, mixed $value, integer $expire=0, ICacheDependency $dependency=NULL)
abstract public mixed get(string $id)

Let's say, you would like to use inside a Yii project the symfony cache library https://packagist.org/packages/symfony/cache with it's cache interface, by defining this service in Yii services components (service locator) configuration https://github.com/symfony/cache-contracts/blob/master/CacheInterface.php

    public function get(string $key, callable $callback, float $beta = null, array &$metadata = null);

We see, symfony cache has an interface with only a get method, missing a set method and a different signature for a get method, as Symfony uses the get method also as a setter when supplying the second callable parameter.

As Yii core internally uses this Yii cache/interface, it's difficult (extending Yii/YiiBase) if not impossible at places , to rewrite the calls to that interface.

Plus Symfony cache is nor our class, so we can't rewrite it's interface to fit with the Yii cache interface.

So here comes the adapter pattern to rescue. We will write a mapping = an intermediate adapter which will map the Yii cache interface calls to Symfony cache interface

Would look like this

    class YiiToSymfonyCacheAdapter implements \Yii\system\caching\ICache
    {
        private \Symfony\Contracts\Cache\CacheInterface $symfonyCache;

        public function __construct(\Symfony\Contracts\Cache\CacheInterface $symfonyCache)
        {
            $this->symfonyCache = $symfonyCache;
        }

      
      public boolean set(string $id, mixed $value, integer $expire=0, ICacheDependency 
       $dependency=NULL) 
      {

          // https://symfony.com/doc/current/cache.html
          return $this->symfonyCache->get(
              $id, 
              function($item) { 
              // some logic .. 
               return $value; 
              }
          );

//          https://github.com/symfony/cache/blob/master/Adapter/MemcachedAdapter.php
// if a class could be called statically, the adapter could call statically also eg. like this
//          return \Symfony\Component\Cache\Adapter\MemcacheAdapter::get(
//              $id, 
//              function($item) { 
//              // some logic .. 
//               return $value; 
//              }
          );
       }

       public mixed get(string $id) 
       {
           // https://github.com/symfony/cache/blob/master/Adapter/FilesystemAdapter.php 
           // if a class could be called statically, the adapter could call statically also eg. like this
           // \Symfony\Component\Cache\Adapter\FileSystemAdapter::get($id)
           return $this->symfonyCache->get($id) 
       }
    } 

Solution 14 - Oop

A real example can be reporting documents in an application. Simple code as here.

Adapters i think are very useful for programming structure.

class WordAdaptee implements IReport{
	public void report(String s) {
		System.out.println(s +" Word");
	}
}

class ExcellAdaptee implements IReport{
	public void report(String s) {
		System.out.println(s +" Excel");
	}
}


class ReportAdapter implements IReport{
	WordAdaptee wordAdaptee=new WordAdaptee();
	@Override
	public void report(String s) {
		wordAdaptee.report(s);
	}
}

interface IReport {
	public void report(String s);
}

public class Main {
	public static void main(String[] args) {
		
		//create the interface that client wants
		IReport iReport=new ReportAdapter();
		
		//we want to write a report both from excel and world
		iReport.report("Trial report1 with one adaptee");  //we can directly write the report if one adaptee is avaliable 
		
		//assume there are N adaptees so it is like in our example
		IReport[] iReport2={new ExcellAdaptee(),new WordAdaptee()};
		
		//here we can use Polymorphism here  
		for (int i = 0; i < iReport2.length; i++) {
			iReport2[i].report("Trial report 2");
		}
	}
}

Results will be:

Trial report1 with one adaptee Word
Trial report 2 Excel
Trial report 2 Word

Solution 15 - Oop

This is an example of adapter implementation:

interface NokiaInterface {
    chargementNokia(x:boolean):void
}


class SamsungAdapter implements NokiaInterface {
//nokia chargement adapted to samsung
    chargementNokia(x:boolean){
        const old= new SamsungCharger();
        let y:number = x ? 20 : 1;
        old.charge(y);
      }
}


class SamsungCharger {
      charge(x:number){
            console.log("chrgement x ==>", x);
      }
}


function main() {
      //charge samsung with nokia charger
      const adapter = new SamsungAdapter();
      adapter.chargementNokia(true);
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAksharRoopView Question on Stackoverflow
Solution 1 - OopFuhrmanatorView Answer on Stackoverflow
Solution 2 - OopCountZeroView Answer on Stackoverflow
Solution 3 - OopPremrajView Answer on Stackoverflow
Solution 4 - OopEricView Answer on Stackoverflow
Solution 5 - OopbabuView Answer on Stackoverflow
Solution 6 - OopJaabaxView Answer on Stackoverflow
Solution 7 - OopSumanth VaradaView Answer on Stackoverflow
Solution 8 - OopBillView Answer on Stackoverflow
Solution 9 - OopdexterousView Answer on Stackoverflow
Solution 10 - OopJustice O.View Answer on Stackoverflow
Solution 11 - Ooprahil008View Answer on Stackoverflow
Solution 12 - OopCBUView Answer on Stackoverflow
Solution 13 - OopFantomX1View Answer on Stackoverflow
Solution 14 - OophuseyinView Answer on Stackoverflow
Solution 15 - OopOmar MarzouguiView Answer on Stackoverflow