Z. QIU
Posted on December 7, 2020
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.
Posted on December 7, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.