JS: Polimorfismo

Teoría: Patrón de Objeto Nulo

En los sitios web que tienen autenticación, existe el concepto de "usuario actual". Este es el usuario que se ha autenticado a través de un formulario o de una red social. El usuario actual se utiliza frecuentemente para mostrar varios bloques de información, como por ejemplo, el blog de ese usuario. El código suele verse así:

// en algún lugar de la plantilla imaginaria articles/index.html.slim

if isAuthenticated && currentUser.hasArticles()
  each article in currentUser.getArticles()
    // aquí mostramos los artículos

Observa la verificación de la autenticación del usuario. Si no se hace, el código dará un error porque se llama al método hasArticles() en un objeto nulo (null), ya que el usuario no está presente si no ha iniciado sesión. Cuando estas verificaciones son una o dos, no hay problema, pero si son muchas, el código se llena rápidamente de ellas. Además, es fácil olvidar insertar una de estas verificaciones.

¿Se puede resolver este problema de otra manera? Resulta que sí. Solo necesitas usar el polimorfismo de subtipos. Para esto, se crea una clase que describe a un usuario no autenticado, por ejemplo, Guest. Luego se añaden todos los métodos necesarios para los cuales queremos obtener un comportamiento polimórfico.

class Guest {
  hasArticles() {
    return false;
  }

  getArticles() {
    return [];
  }
}

La mayoría de estos métodos devuelven false o listas vacías, ya que este usuario no tiene nada. ¿Entonces para qué sirve? Todo es muy simple: ahora el código del cliente siempre asume que el usuario existe y ya no necesita verificar la autenticación:

if currentUser.hasArticles()
  each article in currentUser.getArticles()
    // aquí mostramos los artículos

Las construcciones condicionales desaparecerán de todas las plantillas, pero queda una pregunta. ¿Dónde y cómo se produce el proceso de creación de nuestro usuario? Y aquí es donde queda ese único if, gracias al cual se creará el objeto correcto. Esto ocurre durante el procesamiento de la solicitud entrante, y el lugar y la forma concreta dependen del framework utilizado. El código en este lugar se ve aproximadamente así:

const fetchCurrentUser = (req) => {
    const userId = req.session.userId;
    // Si hay un id en la sesión, seleccionamos al usuario de la base de datos, de lo contrario, devolvemos un invitado
    return userId ? User.find(userId) : new Guest();
};

Este uso del polimorfismo tiene un nombre especial: patrón de diseño null object. Se usa a menudo dentro de los frameworks y a veces se encuentra en el código de aplicación. En Códica, hay al menos 3 lugares donde se usa este patrón. Por ejemplo, en la clase Guest tenemos decenas de métodos.

# Código en Ruby, pero es simple como dos centavos
class Guest
  def id
    nil
  end

  def avatar
    nil
  end

  def github_account
    false
  end

  def has_passed_at_least_one_project?
    false
  end

  def city
    ''
  end

  def seeking_job?
    true
  end

  def mentor?
    false
  end

  def locale?
    nil
  end

  def guest?
    true
  end

  def current_subscription_object
    FreeSubscription.new(self)
  end

  def type
    'guest'
  end

  def topics_count
    0
  end
end

Completado

0 / 14