Adapter design pattern
The adapter pattern can be used as a bridge between two incompatible interfaces. This type of design pattern is a structural pattern because this pattern combines the functionality of two separate interfaces.
This pattern involves a class that is responsible for wiring the functionality of independent or incompatible interfaces. A real-world example is a card reader, which is an adapter between a memory card and a laptop. You plug the memory card into the card reader, and you plug the card reader into the laptop so that the memory card can be read by the laptop.
Adapter design pattern helps classes to work together. It converts the interface of one class to another interface on demand. The pattern includes a polymorphism, which names a name and forms. Based on the collected requirements, generate a used shape class.
There are two types of adapter pattern −
- Object Adapter Pattern - This design pattern relies on object implementation. Hence, it is called Object Adapter pattern.
- Class Adapter Pattern - This is another way of implementing the Adapter design pattern. This pattern can be implemented using multiple inheritance.
How to implement the adapter pattern?
Now let's see how to implement the Adapter pattern. Refer to the following code
class EuropeanSocketInterface: def voltage(self): pass def live(self): pass def neutral(self): pass def earth(self): pass # Adaptee class Socket(EuropeanSocketInterface): def voltage(self): return 230 def live(self): return 1 def neutral(self): return -1 def earth(self): return 0 # Target interface class USASocketInterface: def voltage(self): pass def live(self): pass def neutral(self): pass # The Adapter class Adapter(USASocketInterface): __socket = None def __init__(self, socket): self.__socket = socket def voltage(self): return 110 def live(self): return self.__socket.live() def neutral(self): return self.__socket.neutral() # Client class ElectricKettle: __power = None def __init__(self, power): self.__power = power def boil(self): if self.__power.voltage() > 110: print "Kettle on fire!" else: if self.__power.live() == 1 and \ self.__power.neutral() == -1: print "Coffee time!" else: print "No power." def main(): # Plug in socket = Socket() adapter = Adapter(socket) kettle = ElectricKettle(adapter) # Make coffee kettle.boil() return 0 if __name__ == "__main__": main()
Execute the above sample code to get the above result
Explanation: The code includes an adapter interface with various parameters and properties. It includes Adaptee and Target interfaces, which implements all properties and displays output as visible.
Decorator design pattern
The decorator pattern allows users to add new functionality to an existing object without changing its structure. This type of design pattern is a structural pattern because this pattern acts as a wrapper around an existing class.
This pattern creates a decorator class that wraps the original class and provides additional functionality, keeping the class method signature intact.
The motivation of the decorator pattern is to dynamically attach extra responsibilities (functionality) to an object.
How to implement the Decorator design pattern?
The code mentioned below is a simple demonstration of how to implement the decorator design pattern in Python. The example involves representing a coffee shop (class coffeeshop) as a class. The created coffee class is an abstract class, which means it cannot be instantiated
import six from abc import ABCMeta @six.add_metaclass(ABCMeta) class Abstract_Coffee(object): def get_cost(self): pass def get_ingredients(self): pass def get_tax(self): return 0.1*self.get_cost() class Concrete_Coffee(Abstract_Coffee): def get_cost(self): return 1.00 def get_ingredients(self): return 'coffee' @six.add_metaclass(ABCMeta) class Abstract_Coffee_Decorator(Abstract_Coffee): def __init__(self,decorated_coffee): self.decorated_coffee = decorated_coffee def get_cost(self): return self.decorated_coffee.get_cost() def get_ingredients(self): return self.decorated_coffee.get_ingredients() class Sugar(Abstract_Coffee_Decorator): def __init__(self,decorated_coffee): Abstract_Coffee_Decorator.__init__(self,decorated_coffee) def get_cost(self): return self.decorated_coffee.get_cost() def get_ingredients(self): return self.decorated_coffee.get_ingredients() + ', sugar' class Milk(Abstract_Coffee_Decorator): def __init__(self,decorated_coffee): Abstract_Coffee_Decorator.__init__(self,decorated_coffee) def get_cost(self): return self.decorated_coffee.get_cost() + 0.25 def get_ingredients(self): return self.decorated_coffee.get_ingredients() + ', milk' class Vanilla(Abstract_Coffee_Decorator): def __init__(self,decorated_coffee): Abstract_Coffee_Decorator.__init__(self,decorated_coffee) def get_cost(self): return self.decorated_coffee.get_cost() + 0.75 def get_ingredients(self): return self.decorated_coffee.get_ingredients() + ', vanilla'
The implementation of the coffeeshop abstract class is done through a separate file as described below
import coffeeshop myCoffee = coffeeshop.Concrete_Coffee() print('Ingredients: '+myCoffee.get_ingredients()+ '; Cost: '+str(myCoffee.get_cost())+'; sales tax = '+str(myCoffee.get_tax())) myCoffee = coffeeshop.Milk(myCoffee) print('Ingredients: '+myCoffee.get_ingredients()+ '; Cost: '+str(myCoffee.get_cost())+'; sales tax = '+str(myCoffee.get_tax())) myCoffee = coffeeshop.Vanilla(myCoffee) print('Ingredients: '+myCoffee.get_ingredients()+ '; Cost: '+str(myCoffee.get_cost())+'; sales tax = '+str(myCoffee.get_tax())) myCoffee = coffeeshop.Sugar(myCoffee) print('Ingredients: '+myCoffee.get_ingredients()+ '; Cost: '+str(myCoffee.get_cost())+'; sales tax = '+str(myCoffee.get_tax()))
Executing the above program produces the following output