Today I would like to do some coding work on Adapter Pattern in Python. 
Adapter is one of the Structural Patterns.
It works as a bridge between two incompatible interfaces. This pattern involves a single class which is responsible to join functionalities of independent or incompatible interfaces.
I found easily one real life example of "adapter" in my room. I have a laptop of brand Redmi which has a chinese type power plug. I am living in France and thus I have only European type socket at home. It's not possible to insert directly my laptop's plug into a french socket. 

To solve the issue, I am using an adapter to charge my laptop. This small gadget is really very practical for me. 

Thus I would like to code this example in Python today. Let's go!
1st simulation: Incompatible issue
Socket simulation
Firstly I define several classes for sockets including PowerSocket base class and its concrete classes.
class PowerSocket():
    """
       PowerSocket base class 
    """
    def __init__ (self, holeNum, Shape, Volt):
        self.__num_holes = holeNum
        self.__hole_shape = Shape
        self.__volt = Volt
    def getHoleNum (self):
        return self.__num_holes 
    def getHoleShape (self):
        return self.__hole_shape 
    def getVolt (self):
        return self.__volt 
### some concrete PowerSocket classes
class chineseSocket(PowerSocket):
    def __init__ (self):
        super().__init__( 3, "FLAT", 220)  
class europeanSocket(PowerSocket):
    def __init__ (self):
        super().__init__( 2, "ROUND", 220)          
class taiwaneseSocket(PowerSocket):
    def __init__ (self):
        super().__init__( 2, "FLAT", 110) 
Laptop simulation
Now a class of my Laptop with its plug class. Method charge() of RedmiLaptop class shall check if socket is compatible with its power plug.
class chinise3pinPlug():
    def __init__ (self):
        self.pins = 3
        self.volt = 220
        self.pinshape = "FLAT"    
class RedmiLaptop():
    def __init__ (self):
        self.plug = chinise3pinPlug()
    def charge(self, socket, powerInWatt):
        res = False     
        if (isinstance(socket, PowerSocket)):
            res = (self.plug.pins == socket.getHoleNum() )  and \
            (self.plug.pinshape == socket.getHoleShape() ) and  \
            (self.plug.volt == socket.getVolt() )
        else:
            print ("Socket is not instance of PowerSocket")
        if res:
            current = round(powerInWatt / self.plug.volt, 2)
            print("Start charging... Power: {} watt; Socket current: {} am ...".format(str(powerInWatt), str(current)))
        else:
            print("Socket and plug not compatible, impossible to charge.")
        return res
Charging simulation
Now launch the simulation. I move to 3 different areas in this simulation and see if I can charge my laptop there.
if __name__ == "__main__":
    laptop = RedmiLaptop() # instance of my Redmi Laptop
    # I am in china mainland
    chSocket = chineseSocket()
    laptop.charge(socket=chSocket, powerInWatt=235)
    # I am in France
    euSocket = europeanSocket()
    laptop.charge(socket=euSocket, powerInWatt=235)
    # I am in Taipei 
    twSocket = taiwaneseSocket()
    laptop.charge(socket=twSocket, powerInWatt=235)
2nd Simulation: adapter usage
Adapter simulation
Now I introduce a SocketAdapter base class as adapter interface for socket conversion. I define a AnyToChineseAdapter concrete class to simulate a multi-usage converter for chinese-type plug of my laptop.  AnyToChineseAdapter has a output socket of chinese type. It implements a core method convert() which is responsible to convert different socket interfaces to chinese type, namely it bridges various socket types to chinese-type plugs.
class SocketAdapter():
    """
       SocketAdapter base class 
    """
    def __init__ (self ):
        pass
    def convert(self ):
        pass
    def getSocket (self):
        pass
class AnyToChineseAdapter(SocketAdapter):
    """
       A concrete SocketAdapter class that can convert any socket to chinese socket
    """
    def __init__ (self):
        super().__init__()
        self.__outSocket = chineseSocket()
        self.__voltRatio = 1
        self.__plug = ""
    def convert(self, fromSocket):
        res = True
        if  isinstance (fromSocket,  chineseSocket):
            self.__voltRatio = 1
            self.__plug = "Chinese format Plug"
            print("Chinese to Chinese using {}".format(self.__plug))
        elif isinstance (fromSocket,  europeanSocket):
            self.__voltRatio = 1
            self.__plug = "European format Plug"
            print("European to Chinese using {}".format(self.__plug))
        elif isinstance (fromSocket,  taiwaneseSocket):
            self.__voltRatio = 2
            self.__plug = "Taiwanese format Plug"
            print("Taiwanese to Chinese using {}".format(self.__plug))
        # elif     isinstance (fromSocket,  someSocket):
        #    do converting stuff...
        else:        
            print("Unknown socket, cannot choose plug format and volt convertion ratio")
            res = False
        return res
    def getSocket(self):
        return self.__outSocket
    def getVoltRatio(self):
        return self.__voltRatio
Socket simulation
I define PowerSocket base class and its concrete classes. This part is almost the same as in the first simulation. I define one extra class martianSocket for simulating socket on Mars.
class PowerSocket():
    """
       PowerSocket base class 
    """
    def __init__ (self, holeNum, Shape, Volt):
        self.__num_holes = holeNum
        self.__hole_shape = Shape
        self.__volt = Volt
    def getHoleNum (self):
        return self.__num_holes 
    def getHoleShape (self):
        return self.__hole_shape 
    def getVolt (self):
        return self.__volt 
### some concrete PowerSocket classes
class chineseSocket(PowerSocket):
    def __init__ (self):
        super().__init__( 3, "FLAT", 220)
class europeanSocket(PowerSocket):
    def __init__ (self):
        super().__init__( 2, "ROUND", 220)   
class taiwaneseSocket(PowerSocket):
    def __init__ (self):
        super().__init__( 2, "FLAT", 110)  
class martianSocket(PowerSocket):
    def __init__ (self):
        super().__init__( 2, "FLAT", 300)          
Laptop simulation
A modification in Laptop class regarding the 1st simulation is that now it has a private member __adapter which is an instance of AnyToChineseAdapter. A new method addAdapter should be called to attach a SocketAdapter instance.
class chinise3pinPlug():
    def __init__ (self):
        self.pins = 3
        self.volt = 220
        self.pinshape = "FLAT"    
class RedmiLaptop():
    def __init__ (self):
        self.plug = chinise3pinPlug()
        self.__adapter = None
    def addAdapter(self, adpt):
        self.__adapter = adpt
    def charge(self, inSocket, powerInWatt):
        res = False   
        if (isinstance(inSocket, PowerSocket)) :
            if self.__adapter.convert(inSocket):
                socket = self.__adapter.getSocket()
                res = (self.plug.pins == socket.getHoleNum() )  and \
                (self.plug.pinshape == socket.getHoleShape() ) and  \
                (self.plug.volt == socket.getVolt() )
            else:
                res = False 
        else:
            print ("Socket is not instance of PowerSocket")
        if res:
            current = round(powerInWatt / self.plug.volt, 2) * self.__adapter.getVoltRatio()
            print("Start charging... Power: {} watt; Socket current: {} am ...".format(str(powerInWatt), str(current)))
        else:
            print("Socket and plug not compatible, impossible to charge.")
        return res
Charging simulation
Now launch the 2nd simulation. I move firstly to 3 different areas on earth and finally go on Mars in this simulation and see if I can charge my laptop there.
if __name__ == "__main__":
    redmiAd = AnyToChineseAdapter()
    laptop = RedmiLaptop()
    laptop.addAdapter(redmiAd)
    # I am in china mainland
    chSocket = chineseSocket()
    laptop.charge(chSocket, powerInWatt=235)
    # I am in France
    euSocket = europeanSocket()
    laptop.charge(euSocket, powerInWatt=235)
    # I am in Taipei 
    twSocket = taiwaneseSocket() 
    laptop.charge(twSocket, powerInWatt=235)
    # I am on Mars
    msSocket = martianSocket()
    laptop.charge(msSocket, powerInWatt=235)
See, I can charge my laptop with chinese, european and taiwanese sockets. However, I cannot charge it on Mars, since the adapter does not (yet) have conversion method for martian socket type.
 
 
              
 
    
Top comments (1)
this would find me so useful....