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