Translate

Mostrando las entradas con la etiqueta Patterns. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Patterns. Mostrar todas las entradas

sábado, 11 de julio de 2026

Polimorfismo vs Pattern Matching


Durante los últimos años aparecieron innumerables artículos anunciando la muerte del polimorfismo. La llegada de sealed classes, union types y pattern matching hizo que muchos comenzaran a tratar la orientación a objetos como una técnica del pasado.

Sin embargo, las críticas al polimorfismo no son nuevas. Tampoco las críticas al pattern matching. De hecho, muchas de ellas fueron formuladas por las personas que diseñaron estos paradigmas mucho antes de que existieran Java, Kotlin o Rust.

Vale la pena volver a esas discusiones:


Agregar operaciones es difícil

Philip Wadler formuló en 1998 el famoso Expression Problem.

Su observación sigue siendo una de las críticas más fuertes al polimorfismo: los sistemas orientados a objetos hacen muy sencillo incorporar nuevos tipos, pero extremadamente costoso agregar nuevas operaciones.

Cada nueva operación obliga a modificar toda la jerarquía de clases.

Desde esta perspectiva, el pattern matching invierte completamente el problema: agregar una operación suele consistir simplemente en escribir una nueva función.

No es casualidad que muchos desarrolladores funcionales vean al patrón Visitor como una consecuencia directa de esta limitación.


El comportamiento queda disperso

Martin Odersky ha defendido repetidamente el pattern matching como una herramienta para expresar algoritmos completos en un único lugar.

Cuando la lógica está distribuida entre decenas de implementaciones distintas, comprender una operación completa implica recorrer buena parte del proyecto.

Con pattern matching, el algoritmo aparece concentrado y resulta mucho más sencillo razonar sobre él.

La pregunta implícita es incómoda para la orientación a objetos: ¿Queremos organizar el código alrededor de los datos o alrededor de las operaciones?


El despacho dinámico oculta demasiado

Otra crítica frecuente desde el mundo funcional es que el polimorfismo sacrifica legibilidad en favor de la extensibilidad.

Una llamada aparentemente inocente puede terminar ejecutando cualquiera de decenas de implementaciones.

El flujo del programa deja de ser evidente y pasa a depender de la jerarquía de tipos.

Para muchos, el pattern matching hace exactamente lo contrario: vuelve explícitas todas las alternativas posibles.


Pattern Matching rompe el encapsulamiento

Si hubiera que elegir una crítica histórica, probablemente sea la de Alan Kay.

Kay insistió durante décadas en que los objetos nunca fueron concebidos como estructuras de datos con comportamiento, sino como entidades que colaboran mediante el envío de mensajes.

Desde esa mirada, inspeccionar explícitamente el estado de un objeto para decidir qué hacer significa abandonar el modelo de objetos y volver a programar sobre representaciones internas.

No es una cuestión sintáctica.

Es un cambio de filosofía.


Cada nuevo tipo obliga a revisar todos los matches

Bertrand Meyer, creador de Eiffel y autor del principio Open/Closed, probablemente encontraría aquí su principal objeción.

Cuando aparece un nuevo subtipo, todos los matches relevantes deben ser revisados.

La lógica que antes estaba distribuida vuelve a concentrarse en múltiples lugares.

El costo del cambio deja de estar en agregar operaciones y pasa a estar en agregar variantes del modelo.

Exactamente el problema inverso al planteado por Wadler.


Un match de 500 líneas sigue siendo un switch de 500 líneas

Quizás sea la crítica más práctica.

El pattern matching no garantiza buen diseño.

Nada impide escribir enormes bloques de decisiones difíciles de mantener.

Cambiar la sintaxis de switch por match no elimina automáticamente el acoplamiento ni mejora la modularidad.

Muchas veces simplemente produce un switch más elegante.


Entonces... ¿quién tiene razón?

Probablemente ambos.

Philip Wadler demostró que la orientación a objetos favorece la extensión por tipos.

Bertrand Meyer mostró que esa misma decisión permite mantener el sistema cerrado frente a modificaciones cuando aparecen nuevos comportamientos internos.

Alan Kay defendió durante toda su carrera que los objetos deberían ocultar completamente su representación.

Martin Odersky respondió que muchas veces entender un algoritmo completo es más importante que esconder la representación de los datos.


No son respuestas contradictorias.

Responden preguntas diferentes.


Cada cierto tiempo la industria intenta declarar un ganador.

Hace veinte años parecía que todo debía resolverse con herencia y polimorfismo.

Hoy pareciera que todo debería resolverse con pattern matching.

La realidad es bastante menos interesante para quienes buscan una respuesta definitiva: ninguno reemplaza al otro.


Uno optimiza la evolución del sistema cuando aparecen nuevos tipos.

El otro optimiza la evolución cuando aparecen nuevas operaciones.


No existe una técnica superior.


Existe una pregunta mucho más importante:

¿Qué es lo que cambia con mayor frecuencia en tu dominio?


Porque esa respuesta, mucho más que el paradigma elegido, suele determinar cuál de las dos herramientas encaja mejor.

viernes, 15 de agosto de 2025

Pattern Matching en elm


Aprendimos a crear tipos personalizados con la palabra clave type. Nuestro ejemplo principal fue un usuario en una sala de chat:


type User

  = Regular String Int

  | Visitor String


Los usuarios habituales tienen nombre y edad, mientras que los visitantes solo tienen nombre. Ya tenemos nuestro tipo personalizado, pero ¿cómo lo usamos?

Supongamos que queremos una función toName que decida el nombre que se mostrará para cada usuario. Necesitamos usar una expresión case:


toName : User -> String

toName user =

  case user of

    Regular name age ->

      name

    Visitor name ->

      name


-- toName (Regular "Thomas" 44) == "Thomas"

-- toName (Visitor "kate95")    == "kate95"


La expresión case nos permite ramificar según la variante que veamos, así que, independientemente de si vemos a Thomas o a Kate, siempre sabremos cómo mostrar su nombre.

Y si probamos argumentos inválidos como toName (Visitar "kate95") o toName Anonymous, el compilador nos lo notifica inmediatamente. Esto significa que muchos errores simples se pueden corregir en segundos, en lugar de informar a los usuarios y consumir mucho más tiempo.

La función toName que acabamos de definir funciona de maravilla, pero ¿se da cuenta de que la edad no se utiliza en la implementación? Cuando algunos de los datos asociados no se utilizan, es habitual usar un comodín en lugar de asignarles un nombre:


toName : User -> String

toName user =

  case user of

    Regular name _ ->

      name

    Visitor name ->

      name


El _ reconoce los datos, pero también indica explícitamente que nadie los está utilizando.



martes, 5 de noviembre de 2024

Pattern Matching en Typescript con ts-pattern


En TypeScript, a menudo necesitamos simplificar la lógica de condiciones, y aunque existen alternativas como if-else o switch, estas pueden volverse confusas en estructuras más complejas. Aquí es donde ts-pattern entra en juego, ofreciendo una forma poderosa y funcional de hacer pattern matching. Inspirado en técnicas de lenguajes como Haskell y Scala, ts-pattern permite coincidir patrones de datos y manejar casos de manera clara y estructurada.

ts-pattern es una biblioteca que lleva el pattern matching a TypeScript, haciéndolo flexible y adecuado para manejar varios tipos de datos y patrones complejos. Esto ayuda a escribir código más conciso y fácil de mantener, especialmente en proyectos grandes donde las condiciones exhaustivas son comunes.

Para instalar ts-pattern en tu proyecto, simplemente ejecuta:


npm install ts-pattern



Luego, impórtalo en tu archivo TypeScript:


import { match } from 'ts-pattern';


Veamos un ejemplo básico para entender cómo funciona match en strings:


const saludo = match('hola')

  .with('hola', () => '¡Hola Mundo!')

  .with('adiós', () => '¡Hasta luego!')

  .otherwise(() => 'Desconocido');

console.log(saludo);  // Salida: ¡Hola Mundo!


ts-pattern también permite manejar objetos anidados o arrays, facilitando el trabajo con estructuras más detalladas. Supongamos que tenemos un estado de carga y queremos manejarlo de manera exhaustiva:


type Estado = 'cargando' | 'éxito' | 'error';


const mensaje = match<Estado>('éxito')

  .with('cargando', () => 'Cargando...')

  .with('éxito', () => '¡Datos cargados!')

  .with('error', () => 'Hubo un problema.')

  .exhaustive();

console.log(mensaje);  // Salida: ¡Datos cargados!


Con .exhaustive(), ts-pattern se asegura de que todos los posibles valores de `Estado` están cubiertos, ayudándote a evitar errores futuros.

ts-pattern simplifica el manejo de múltiples condiciones en TypeScript, mejorando la claridad y la mantenibilidad del código. 

Dejo link: https://github.com/gvergnaud/ts-pattern

viernes, 10 de septiembre de 2021

El patrón observador en la programación reactiva


El patrón Observer es un patrón de diseño en el que hay dos tipos de objetos: observadores y sujetos observables. Un observador es un objeto que observa los cambios de uno o más sujetos; un sujeto es un objeto que mantiene una lista de sus observadores y les notifica automáticamente cuando cambia de estado.

La definición del patrón Observer del libro "Gang of Four" (Design Patterns: Elements of Reusable Object-Oriented Software por Erich Gamma, Richard Helm, Ralph Johnson y John Vlissides, ISBN 0-201-63361-2) es "Defina una dependencia de uno a varios entre objetos para que cuando un objeto cambie de estado, todos sus dependientes sean notificados y actualizados automáticamente".

Este patrón es el núcleo de la programación reactiva. Se ajusta perfectamente al concepto de programación reactiva al proporcionar las estructuras para implementar el mecanismo produce/react

Java SDK implementa el patrón Observer con la clase java.util.Observable y la interfaz java.util.Observer.

class Subject extends java.util.Observable {
    public void doWorkAndNotify() {
        Object result = doWork();
        notifyObservers(result);
    }
}

class MyObserver implements Observer {
    @Override
    public void update(Observable obs, Object item) {
        doSomethingWith(item)
    }
}

La clase Subject extiende java.utils.Observable y es responsable de producir un objeto y notificar a los observadores tan pronto como se haya producido el elemento.

MyObserver implementa Observer y es responsable de observar al sujeto y consumir todos los elementos que produce el sujeto.

Veamos como interactuan estos objetos: 

MyObserver myObserver = new MyObserver();
Subject subject = new Subject();
subject.addObserver(myObserver);
subject.doWorkAndNotify();

Desafortunadamente, esta implementación se revela demasiado simple cuando comienza a escribir una lógica más compleja. No se utilizan estas implementaciones.

sábado, 20 de marzo de 2021

Pattern Matching para instanceof en java 16

 


Ya hable de java 16, ahora vamos a ver una de sus mejoras: Pattern Matching para instanceof

Antes de esta característica hacíamos esto : 

if (obj instanceof String) {

    String s = (String) obj;    // grr...

    ...

}

luego de java 16, podemos resolver el casteo de la siguiente manera : 

if (obj instanceof String s) {

    // Y aca usamos s como un string

    ...

}

Dejo link : https://openjdk.java.net/jeps/394

viernes, 12 de marzo de 2021

Libros Gratuitos de Java Code Geeks

 

Download IT Guides!

 

JMeter Tutorial

JMeter is an application that offers several possibilities to configure and execute load, performance and stress tests using different technologies and protocols. It allows simulating...

 
 

Java Design Patterns

A design pattern is a general reusable solution to a commonly occurring problem within a given context in software design. A design pattern is not a finished design that can be...

 
 

Elasticsearch Tutorial

Elasticsearch is a search engine based on Lucene. It provides a distributed, multitenant-capable full-text search engine with an HTTP web interface and schema-free JSON documents....

 
 

Docker Containerization Cookbook

Docker is the world's leading software containerization platform. Docker containers wrap a piece of software in a complete filesystem that contains everything needed to run: code,...

 

martes, 19 de mayo de 2020

Design patterns



Quiero recomendar una pagina de patrones de diseño que esta buenisima, trae una descripción de casi todos los patrones con ejemplos y código. El codigo esta en deferentes lenguajes. 


miércoles, 11 de marzo de 2020

Libro gratuito de Java code Geeks

Download IT Guides!

 
The basic Java framework to access the database is JDBC. Unfortunately, with JDBC, a lot of hand work is needed to convert a database query result into Java classes. Other disadvantages...
 
 
Microservices are a software development technique – a variant of the service-oriented architecture (SOA) structural style – that arranges an application as a collection of loosely...
 
 
JMeter is an application that offers several possibilities to configure and execute load, performance and stress tests using different technologies and protocols. It allows simulating...
 
 
A design pattern is a general reusable solution to a commonly occurring problem within a given context in software design. A design pattern is not a finished design that can be...

martes, 8 de octubre de 2019

Design Patterns in Go



Quiero compartir esta gran pagina que muestra implementaciones de los patrones de diseño GOF en Go. Sería GOF en Go. Esta bueno como nombre de la página "Gof in Go" , bueno...

Ustedes pensarán igual que yo, como van implementar patrones Gof si Go no es orientado a objetos, pero si, con su polimorfismo en las estructuras, puede.

La verdad es que me cautiva porque en tantas cosas no estoy de acuerdo con esta pagina, pero a la vez me parece un genial ejercicio para aprender. Por ejemplo cuando afirma que Go es orientado a objetos pero no tiene ni clases, ni objetos. No sé, por algun lado no me cierra.

En fin, esta en castellano, así que aprovechen. 

Dejo link: https://www.designpatternsingo.com/

lunes, 28 de noviembre de 2016

Javaslang 3.0, haciendo funcional a Java !



Javaslang, es una librería open source que provee estructuras de control y estructuras de datos diseñados con una mentalidad funcional para Java 8. Hace muy poco libero su versión 3.0

Con la introducción de lambdas (λ) en Java 8, las posibilidades son muchísimas, una muy clara es utilizar estructuras como listas o arboles, como se realiza en la programación funcional, a la vez tener estructuras inmutables y por que no emular estructuras de control como pattern matching.

Creo que se entiende la idea, sin más veamos ejemplos:

Pattern matching:

Number num = Match(personOption).of(
    Case(Some(Person($())), person -> 1.0d),
    Case(None(), 0)
);

Immutable:

List<String> list = Collections.unmodifiableList(otherList);

// Boom!
list.add("why not?");

Linked List:

// = List(1, 2, 3)
List<Integer> list1 = List.of(1, 2, 3);

// = List(0, 2, 3)
List<Integer> list2 = list1.tail().prepend(0);

Queue:

Queue<Integer> queue = Queue.of(1, 2, 3)
                            .enqueue(4)
                            .enqueue(5);

Resultados Opcionales:

// = Queue(1)
Queue<Integer> queue = Queue.of(1);

// = Some((1, Queue()))
Option<Tuple2<Integer, Queue<Integer>>> dequeued =
        queue.dequeueOption();

// = Some(1)
Option<Integer> element = dequeued.map(Tuple2::_1);

// = Some(Queue())
Option<Queue<Integer>> remaining =
        dequeued.map(Tuple2::_2);

Iterar con Clausuras:

List.of("Java", "Advent").forEach(s -> {
    // side effects and mutation
});

Y puedo seguir!!

Solo debemos agregar la siguiente entrada en mi pom.xml, si uso maven:

<dependencies>
    <dependency>
        <groupId>io.javaslang</groupId>
        <artifactId>javaslang</artifactId>
        <version>2.0.5</version>
    </dependency>
</dependencies>

Que más decir? Solo que en un futuro podríamos esperar que esta funcionalidad este en la jdk.

Dejo link: http://www.javaslang.io/

jueves, 3 de marzo de 2016

Patrones de Diseño en Java

Les quiero recomendar este libro gratuito sobre patrones de diseño utilizando el lenguaje Java. Para los que no saben los patrones de diseño son soluciones genéricas que podemos aplicar a cualquier lenguaje. En este libro se utiliza Java.



Patrones de Diseño en Java 
Los 23 Modelos de Diseño
Paginas 227

miércoles, 2 de enero de 2013

Encapsular lo que varia




Termine el libro de Patrones de Erich Gamma. La verdad muy bueno, me intereso mucho como muestra los patrones desde un lenguaje dinamicamente tipado como SmallTalk y desde otro estaticamente tipado como C++. Les dejo unos párrafos que me gustaron, que tratan de describir la mayoría de los patrones de comportamiento:

Encapsular aquello que puede variar es el tema de muchos patrones de comportamiento. Cuando un determinado aspecto de un programa cambia con frecuencia, estos patrones definen un objeto que encapsula de dicho aspecto. De esta manera, otras partes del programa pueden colaborar con el objeto siempre que dependan de ese aspecto. Los patrones normalmente definen una clase abstracta que describe el objeto encapsulado, y el patrón toma su nombre de ese objeto. Por ejemplo:

  • Estrategia: encapsula un algoritmo.
  • Estado: encapsula un comportamiento dependiente del estado.
  • Mediador: encapsula el protocolo entre objetos.
  • Iterador: encapsula el modo de acceder y recorrer una colección. 

Estos patrones describen aspectos de un programa que probablemente cambien. La mayoría de los patrones tienen dos tipos de objetos: el nuevo objeto que encapsula y el objeto existente que usa un nuevo objeto creado. Normalmente si no fuera por el patrón, la funcionalidad de los nuevos objetos seria una parte integral de los existentes. Por ejemplo, el código de una Estrategia probablemente estaría ligado al contexto de la estrategia, y el código de un Estado se encontraría implementado directamente en el contexto del estado.

Pero no todos los patrones de comportamiento de objeto dividen así la funcionalidad. Por ejemplo, el patrón Chain of Responsibility trata con un numero indeterminado de objetos, cada uno de los cuales puede que ya exista en el sistema

El patrón Chain of Responsibility muestra otra diferencia entre los patrones de comportamiento: no todos definen relaciones de comunicación estática entre las clases. El patrón Chain of Responsibility describe el modo de comunicación entre un numero indefinido de objetos. Otros patrones usan objetos que se pasan como parámetros.

Como conclusión solo les puedo recomendar que lean "Patrones de Diseño" de Erich Gamma.

domingo, 17 de junio de 2012

Herencia frente a composición

Estoy leyendo Patrones de Diseño de Erich Gamma. En este libro discute sobre como es mejor reutilizar funcionalidad si por medio de la herencia o la composición. La idea de este post no es transcribir del libro sino hacer un resumen y analizar cada punto.

Vamos primero con la composición, la composición es una técnica en la cual descomponemos objetos para reutilizar funcionalidad. De esta forma componiendo objetos podemos obtener funcionalidad más compleja y completa.

Ventajas:

  • Reutilización de caja negra, los detalles internos de los objetos no son visibles.
  • La dependencia de objetos se puede definir dinamicamente si utilizamos interfaces. Disminuyendo el acoplamiento y aumentando la reutilización. 
  • Ayuda a mantener cada clase encapsulada y centrada en una sola tarea. De esta manera, nuestra clases y jerarquías de clases permanecerán pequeñas y sera menos probable que se conviertan en monstruos inmanejables. 
Desventajas:
  • Requiere más diseño (que tampoco es tan malo)
El mecanismo de herencia lo conocemos bien y también tiene sus ventajas y desventajas


Ventaja:

  • Es facil de usar lo provee los lenguajes.
  • Es más fácil modificar la implementación que esta siendo reutilizada. 
Desventaja:
  • Reutilización de caja blanca, los hijos pueden modificar variables internas del padre (si están protegidas o publicas), la herencia suele decirse rompe el encapsulamiento. 
  • Existe más acoplamiento ya que cualquier cambio en el padre obligara a cambiar la subclase. 
Según lo dicho podemos afirmar:

"Favorecer la composición de objetos frente a la herencia de clases."


Idealmente, solo crearíamos nuevos componentes para lograr la reutilización. Deberíamos ser capases de conseguir toda la funcionalidad que necesitamos simplemente ensamblando componentes existentes a través de la composición de objetos. Sin embargo, rara vez este es el caso, por lo tanto reutilizar mediante herencia hace más fácil construir nuevos componentes que puedan ser combinados con los antiguos. La herencia y la composición trabajan juntas. Pero abusar de la herencia trae consigo diseños más complejos y utilizar composición hace más fácil y reutilizable el diseño. 

sábado, 2 de julio de 2011