python design pattern - adapter design pattern, decorator design pattern

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

Tags: Python Design Pattern programming language

Posted by madwormer2 on Sun, 05 Feb 2023 23:08:57 +1030