Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
December 7, 2020 10:12 am GMT

Design Pattern in Python (4): Adapter Pattern

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.

Alt Text

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.
Alt Text

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

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 classesclass 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) 
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

Execution output:
Alt Text

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):        passclass 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
Enter fullscreen mode Exit fullscreen mode

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 classesclass 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)          
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

Execution output:
Alt Text

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.


Original Link: https://dev.to/jemaloq/design-pattern-in-python-4-adapter-pattern-g74

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To