Fábricas de clases: un poderoso patrón en Python

Una fábrica de clases es una función que crea y devuelve una clase. Es uno de los poderosos patrones en Python. En esta sección, cubriremos cómo diseñar fábricas de clases y los casos de uso de la misma.

Diseño de una fábrica de clases 

Como se mencionó, las fábricas de clases son funciones que crean y devuelven una clase. Puede crear una clase en el momento de la codificación (usando la palabra clave class) y también durante el tiempo de ejecución (usando el tipo). Comencemos con cómo diseñar una fábrica de clases y crear una clase en el momento de la codificación, luego veremos el escenario de la creación de una clase durante el tiempo de ejecución.

Class Factory y palabra clave de clase

Diseñar una fábrica de clases usando la palabra clave class no es más que crear una función que contenga una clase. Veamos el siguiente código:

Python3

def apple_function():
    """Return an Apple class, built using the 
    class keyword"""
    class Apple(object):
        def __init__(self, color):
            self.color = color
  
        def getColor(self):
            return self.color
    return Apple
  
  
# invoking class factory function
Apple = apple_function()
appleObj = Apple('red')
print(appleObj.getColor())
Producción

red

Clase Fábrica y tipo

Usando type podemos crear clases dinámicamente. Pero hacerlo dejará las funciones en el espacio de nombres junto con la clase. Veamos el código para entenderlo mejor.

Python3

def init(self, color):
    self.color = color
  
  
def getColor(self):
    return self.color
  
  
Apple = type('Apple', (object,), {
    '__init__': init,
    'getColor': getColor,
})
  
appleRed = Apple(color='red')
print(appleRed.getColor())
Producción

red

El código anterior muestra cómo crear una clase dinámicamente. Pero el problema es que las funciones como init y getColor están saturando el espacio de nombres y tampoco podremos reutilizar la funcionalidad. Mientras que, al usar una fábrica de clases, puede minimizar el desorden y puede reutilizar la función cuando sea necesario. Veamos el siguiente código.

Python3

def create_apple_class():
    def init(self, color):
        self.color = color
  
    def getColor(self):
        return self.color
  
    return type('Apple', (object,), {
        '__init__': init,
        'getColor': getColor,
    })
  
  
Apple = create_apple_class()
appleObj = Apple('red')
print(appleObj.getColor())
Producción

red

Es importante tener en cuenta que varias llamadas a create_apple_class devolverán clases distintas.

Cuándo debes escribir Fábricas de clase

Echemos un vistazo a algunos de los casos de uso de las fábricas de clases. Las fábricas de clases son útiles cuando no sabe qué atributos se asignarán en el momento de la codificación. 

Atributos de tiempo de ejecución

Las fábricas de clase son necesarias cuando los atributos de la clase difieren según el requisito. Consideremos el caso de un proceso de inicio de sesión. Aquí, consideraremos dos escenarios, ya sea el inicio de sesión tradicional o el uso de un servicio OpenId. Si nos fijamos en el inicio de sesión tradicional, los parámetros son nombre de usuario y contraseña, y además, puede tener autenticación de dos factores. Y, para el servicio OpenId, los parámetros son el nombre del servicio y la dirección de correo electrónico. Este escenario de dos inicios de sesión apunta al hecho de que los atributos de una clase difieren según el servicio de inicio de sesión. Veamos el siguiente código de ejemplo:  

Python3

def credentials_cls(need_proxy=False, tfa=False):
    # need proxy for openId services
    if need_proxy:
        print("Open Id Service")
        keys = ['service_name', 'email_address']
    else:
        print("Traditional Login")
        keys = ['username', 'password']
  
        # two factor authentication for traditional login
        if tfa:
            keys.append('auth_token')
  
    class CredentialCheck(object):
        required_keys = set(keys)
  
        def __init__(self, **kwargs):
            # checking whether key matches based on login service
            if self.required_keys != set(kwargs.keys()):
                raise ValueError('Mismatch')
  
            # storing the keys and values to the credential object
            for k, v in kwargs.items():
                setattr(self, k, v)
  
    return CredentialCheck
  
  
CredCheck = credentials_cls(False, False)
crdTraditional = CredCheck(username='uname', password='******')
  
OpenIDCheck = credentials_cls(True, False)
crdOpenID = OpenIDCheck(service_name='sname', email_address='email@gmail.com')
Producción

Traditional Login
Open Id Service

Modificar atributos de clase

Otra ventaja de usar atributos de clase es que puede manejar atributos de clase y distinguirlos de instancias de clase. Consideremos el escenario donde una clase define un método de clase. Los métodos de clase son métodos que requieren la clase misma para su ejecución en lugar de la instancia de una clase. Puede diseñar un método de clase decorando un método usando el decorador @classmethod. Veamos el siguiente código.

Python3

class Apple(object):
    color = 'red'
  
    @classmethod
    def classapple(cls):
        return cls.color
  
  
appleRed = Apple()
appleYellow = Apple()
appleGreen = Apple()
  
print("Apple Red: ", appleRed.classapple())
  
appleYellow.color = 'Yellow'
print("Apple Yellow: ", appleYellow.classapple())
  
appleGreen.color = 'Green'
print("Apple Green: ", appleGreen.classapple())
Producción

Apple Red:  red
Apple Yellow:  red
Apple Green:  red

En el código anterior, hemos diseñado una clase llamada Apple que tiene color como atributo. Además de esto, hemos declarado un método de clase llamado classapple usando el decorador @classmethod . La funcionalidad del método classapple es devolver el color de la manzana. Pero puede notar que incluso después de establecer el color de la manzana en amarillo y verde, el objeto devuelve el color rojo predeterminado. Esta limitación se puede superar utilizando una fábrica de clases. 

Veamos el siguiente código que define una fábrica de clases llamada create_Apple_subclass. Aquí crearemos una subclase de Apple, subApple, para establecer el color. Finalmente, la fábrica de clases devuelve la subclase. 

Python3

class Apple(object):
    color = 'red'
  
    @classmethod
    def classapple(cls):
        return cls.color
  
  
def create_Apple_subclass(new_color):
    class SubApple(Apple):
        color = new_color
    return SubApple
  
  
sappleYellow = create_Apple_subclass('Yellow')
print("Apple Color: ", sappleYellow.classapple())
  
sappleGreen = create_Apple_subclass('Green')
print("Apple Color: ", sappleGreen.classapple())
Producción

Apple Color:  Yellow
Apple Color:  Green

Resumen

Las fábricas de clases son poderosos patrones de diseño que aseguran que un proceso dinámico de creación de clases sea legible, organizado y reutilizable. Y, también, las fábricas de clases permiten el cambio de atributos en función del parámetro enviado a la función.

Publicación traducida automáticamente

Artículo escrito por SonuGeorge y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *