Adapter

Buffer this pageShare on FacebookPrint this pageTweet about this on TwitterShare on Google+Share on LinkedInShare on StumbleUpon
Reading Time: 1 minutes

Adapter Design Pattern in Python

Adapter Design Pattern in Python

Design Patterns Home
 

What is it?

The Adapter Design Pattern helps to convert the interface of a class into another interface that the client expects. For example, an electric kettle with square-pinned plug (client) expects to have a square-pin socket. But the wall-socket (our existing class) has round pins. The pin converter (adapter) comes to the rescue.

Another example, a French-only speaking person (client) wishes to have a two-way communication in French, and hence expects another person to know French. But an English-only speaking person (our existing class) cannot understand French. The English-French translator who knows both French and English (adapter) serves the purpose.

It is classified under Structural Design Patterns as it offers one of the best ways to organize class hierarchy.


Why the need for it: Problem Statement

The Adapter Pattern is needed when the interface of an existing class needs to be morphed into one that the client wants.


Terminology

  • Adaptee: The existing class whose interface needs to be morphed.
  • Adapter: The class in charge of morphing the interface of the adaptee to cater to client's needs.
  • Client: The class who wishes that wants to change the interface of an existing class to suit its own needs.

How to implement it

# Example #1: Language Translator
# Our client, a French-only speaking person, wishes to have a two-way conversation in French. He expects the other person to be able to speak French.
# Our existing class, an English-only speaking person cannot speak French.
# Our Adapter, is in the form of a translator who translates English responses to French so that our French-only speaking client can have his two-way conversation in French.

# Existing Class: a.k.a. Adaptee: Incompatible interface # 1
class EnglishSpeaker:
        def responseToGreeting(self):
                return "Hello to you too!"
        def responseToFarewell(self):
                return "Goodbye my friend."

# Adapter Class, which takes functionality provided by EnglishSpeaker, morphs it into functionality expected by the FrenchSpeaker.
class Translator:
		'''Accespts an english speaker, translates his responses to French.'''
        _englishSpeaker = None
        _englishToFrenchPhrases = {
                "Hello to you too!": "Bonjour à vous aussi",
                "Goodbye my friend.": "Au revoir mon ami"
                }
                
        def __init__(self, englishSpeaker):
                self._englishSpeaker = englishSpeaker
        
# Client: Incompatible interface # 2
class FrenchSpeaker:
		'''Accepts an English-To-French Speaker as argument.'''
        _englishToFrenchTranslator = None

        def __init__(self, englishToFrenchTranslator):
                self._englishToFrenchTranslator = englishToFrenchTranslator

        def exchangeGreetings(self):
                print("Salut!")
                print( self._englishToFrenchTranslator._englishToFrenchPhrases[  self._englishToFrenchTranslator._englishSpeaker.responseToGreeting()  ] )

        def exchangeFarewell(self):
                print("Au revoir!")
                print( self._englishToFrenchTranslator._englishToFrenchPhrases[  self._englishToFrenchTranslator._englishSpeaker.responseToFarewell()  ] )

# Create an English Speaking person
englishSpeaker = EnglishSpeaker()

# Create a translator with popular english phrases
englishToFrenchTranslator = Translator(englishSpeaker)

# The French Speaking Person can now get responses in French
frenchSpeaker = FrenchSpeaker(englishToFrenchTranslator)

# Two-way conversation in French
frenchSpeaker.exchangeGreetings()
frenchSpeaker.exchangeFarewell()

# OUTPUT
Salut!
Bonjour à vous aussi
Au revoir!
Au revoir mon ami
# Example #2: Square-pin to round-pin adapter
# Consider two incompatible interfaces: round-pin Socket & square-pin Electric Kettle. 
# The Electric Kettle expects a square-pin connection for it to work.
# The Adapter takes square-pin of Electric Kettle, and connects to round-pin socket.

# Existing Class: a.k.a. Adaptee: Incompatible interface # 1
class Socket:
    _pinType = "Round"
    
# The Adapter: acts as an interface between two incompatible interfaces
class Adapter:
    _socket = None
    _pinType = "SquareToRound"
    
    def __init__(self, socket):
        self._socket = socket

# Client: Incompatible interface # 2
class ElectricKettle:
    _adapter = None
    _pinType = "Square"

    def __init__(self, adapter):
        self._adapter = adapter
    def makeTea(self):
        if self._adapter._pinType == (self._pinType + "To" + self._adapter._socket._pinType):       # "SquareToRound" == "Square" + "To" + "Round"
            print("Boiling water....")
            print("Adding ingredients...")
            print("Tea brewing...")
            print("Tea is ready!")
        else:
            print("No power. Can't function.")


# Create a socket
roundPinSocket  = Socket()
# Connect adapter and socket
squareToRoundAdapter = Adapter(roundPinSocket)
# Connect Kettle and socket via adapter. 
kettle  = ElectricKettle(squareToRoundAdapter)

kettle.makeTea()

# OUTPUT:

Boiling water....
Adding ingredients...
Tea brewing...
Tea is ready!

Related to: Bridge & Decorator


 

 

 

 


See also:

Buffer this pageShare on FacebookPrint this pageTweet about this on TwitterShare on Google+Share on LinkedInShare on StumbleUpon

Leave a Reply