sirve - Composición del cliente de Scala con Rasgos vs implementación de una clase abstracta
que es una clase abstracta en poo (2)
He leído que con Scala, generalmente se recomienda usar rasgos en lugar de clases abstractas para extender una clase base.
¿Es el siguiente un buen patrón de diseño y diseño? ¿Es así como los Rasgos fueron destinados a reemplazar el Resumen?
- clase de cliente (con def function1)
- clase de trait1 (anula la función1)
- clase de trait2 (anula la función1)
- specificClient1 extiende al cliente con trait1
- specificClient2 extiende el cliente con trait2
No sé cuál es su fuente para afirmar que debe preferir los rasgos sobre las clases abstractas en Scala, pero existen varias razones para no hacerlo:
- Los rasgos complican la compatibilidad de Java. Si tiene un rasgo con un objeto complementario, la invocación de métodos en el objeto complementario de Java requiere la extraña
MyType$.MODULE$.myMethod
. Este no es el caso para las clases abstractas con objetos complementarios, que se implementan en la JVM como una clase única con métodos estáticos y de instancia. Implementar un rasgo de Scala con métodos concretos en Java es aún más desagradable. - Agregar un método con una implementación a un rasgo rompe la compatibilidad binaria de una manera que agregar métodos concretos a una clase no lo hace.
- Los rasgos dan como resultado más bytecode y algunos gastos indirectos adicionales relacionados con el uso de métodos de reenviadores.
- Los rasgos son más potentes, lo cual es malo; en general, desea utilizar la abstracción menos poderosa que hace el trabajo. Si no necesitas el tipo de herencia múltiple que admiten (y muy a menudo no), es mejor no tener acceso a ella.
La última razón es de lejos la más importante desde mi punto de vista. Al menos algunos de los otros problemas podrían solucionarse en versiones futuras de Scala, pero seguirá siendo cierto que el incumplimiento de las clases restringirá sus programas de maneras que (al menos argumentablemente) son consistentes con un buen diseño. Si decides que realmente quieres el poder proporcionado por los rasgos, ellos seguirán allí, pero esa será una decisión que tomarás, no algo en lo que te metes.
Entonces, no, a falta de otra información, sugeriría usar una clase abstracta (idealmente una cerrada) y dos clases concretas que brinden implementaciones.
OTOH, los rasgos te permiten construir y probar la funcionalidad de objetos complejos de forma granular y reutilizar la lógica del núcleo para proporcionar diferentes sabores. Por ejemplo, un objeto de dominio puede implementarse en un servidor de datos, que persiste en una base de datos, mientras que un servidor web puede emplear versiones de solo lectura del mismo objeto que se actualizan desde el servidor de datos.
Nada es adecuado para cada escenario. Use la construcción correcta para la tarea en cuestión. A veces, la realidad de una implementación saca a la luz cuestiones para casos de uso específicos que se desconocían en el momento del diseño. Volver a implementar el uso de diferentes supuestos y construcciones puede dar resultados sorprendentes.