oop - ¿Cómo la Coincidencia de patrones en Scala supera la duplicación que causa el cambio de caso?
design-patterns (5)
Ellos realmente no tienen ese problema exacto si abusas de ellos.
Así como la polimorfía por herencia se mete en problemas cuando hace que sus clases atraigan todo tipo de métodos que realmente no pertenecen a esa clase.
Si bien Java tiene un soporte sólido razonable para heredar, la declaración de cambio es solo una broma.
En Scala tienes un soporte aún mayor para la herencia y la increíble coincidencia de patrones.
Es tu trabajo elegir el martillo adecuado para tu uña.
NOTA: Estoy haciendo esta pregunta por curiosidad y no cuestionando la importancia de una característica del idioma.
Parece ser una gran característica presentada a las personas del imperativo mundo de la programación. Soy nuevo en Scala y todavía estoy tratando de averiguar dónde encajan todos, hacer que sus conjuntos masivos de construcciones encajen y puedan aprovecharse.
La coincidencia de patrones definitivamente puede hacer cosas 100 veces mejor que la caja del interruptor. pero aún así, es una construcción de caso sobre la que usamos para preferir el polimorfismo desde el momento en que salió la POO.
Entonces, en resumen, lo que me resulta difícil de entender es: si el cambio de mayúsculas y minúsculas fomenta la duplicación y es mejor que escribamos el código relacionado con el caso en las clases respectivas, ¿cómo supera esto la coincidencia de patrones de Scala?
Todavía podemos tener clases o clases genéricas para varios casos y nuevamente aprovechar el polimorfismo para nuestra necesidad.
Es la cuestión de la diferencia entre los objetos y las estructuras de datos.
Si está tratando con objetos, utilice el polimorfismo de subtipo: agregar nuevos tipos no requiere recompilación, volver a probar o redistribuir los existentes, mientras que agregar un nuevo algoritmo (un método en la interfaz, que está en la parte superior de la jerarquía) sí lo hace. .
Si está lidiando con estructuras de datos, utilice la coincidencia de patrones: agregar nuevos algoritmos no requiere la recompilación, la reevaluación o la reubicación de los existentes, mientras que agregar un nuevo tipo sí.
Lea más sobre esto here .
La combinación de patrones es una gran característica porque es fácil de usar.
Resuelve el problema de "cómo llevar la funcionalidad a un sistema de objetos" mucho mejor que la mayoría de los patrones de diseño en lenguajes orientados a objetos ampliamente utilizados. Por ejemplo, existe el patrón de visitante , que separa un algoritmo de su estructura de objeto. La idea es genial porque nos permite cambiar el comportamiento de nuestros objetos sin tocar sus clases. Pero en el otro lado, este patrón falla en exceso de complejidad y verbosidad de notación. Con la coincidencia de patrones, esto se puede resolver fácilmente:
def calc(e: Expression): Double = e match {
case Num(n) => n
case Add(a, b) => calc(a)+calc(b)
case Sub(a, b) => calc(a)-calc(b)
...
}
Esto separa el cálculo de un AST de su definición y es mucho mejor leerlo que el patrón de visitante polimórfico.
Debido a que la combinación de patrones es tan fácil, podemos usarla en cualquier parte, la encontrará en lugares en los que nunca ha pensado en la mayoría de los idiomas OO. Un gran ejemplo son los actores, que utilizan tipos de datos algebraicos (ADT) para comunicarse entre sí:
sealed trait Message
case class Hello(name: String) extends Message
case class Bye(name: String) extends Message
case class Question(q: Symbol) extends Message
class MySelf extends Actor {
def receive {
case Hello(name) => println("Hello "+name)
case Bye(name) => println("Buy "+name)
case Question(''AreYouOk) => sender answer "I''m ok"
...
}
}
¡Te deseo mucha diversión implementando esto con el patrón de Visitante!
La herencia y las construcciones de casos son formas válidas de lograr el polimorfismo. Son buenos en situaciones ligeramente diferentes. A diferencia del polimorfismo basado en herencia, la coincidencia de patrón no es extensible, sin embargo, a menudo no es necesario que lo sea. Muchas estructuras en la programación funcional, como la Opción, O cualquiera o :: se pueden usar de manera más concisa con las coincidencias de patrones que forman el polimorfismo oop y las declaraciones if. En general, cualquier problema podría resolverse con cualquier tipo de polimorfismo. Es sólo una cuestión de elegancia.
Veo algunos puntos en los que la coincidencia de patrones completa la POO y permite una programación más modular.
Cuando tienes un gran proyecto, debes evitar poner "demasiado comportamiento" dentro de tus clases de dominio. Puede mover el comportamiento fuera, y normalmente tiene un método que recibe una clase en la parte superior de una jerarquía y coincide con las clases secundarias.
Cuando utiliza bibliotecas específicas y desea agregar comportamiento, no puede modificar las fuentes. También puede usar la conversión implícita para esto, pero en casos simples, la comparación de patrones es más rápida y fácil.
Para responder a su pregunta, probablemente diría que subestima la reutilización del código que puede traer la coincidencia: cuando crea un bloque de coincidencia que crea un PartialFunction . Si necesita reutilizar sus bloques de coincidencia de patrones, puede usar el encadenamiento PartialFunction, a través del método orElse. Esto también ofrece beneficios al diseñar un conjunto jerárquico de manejadores de un objeto específico, ya que las coincidencias se ejecutan en orden.