¿Cuándo usar rasgos, a diferencia de la herencia y la composición?

7

Hay tres formas comunes, AFAIK, para implementar la reutilización cuando se trata de POO

  1. Herencia: por lo general, para representar es una relación (un pato es un pájaro)
  2. Composición: generalmente para representar has-una relación (un automóvil tiene-un motor)
  3. Rasgos (por ejemplo, la palabra clave de rasgo en PHP): ... no estoy realmente seguro de esto

Aunque me parece que los rasgos pueden implementar relaciones has-a y is-a, no estoy realmente seguro de a qué tipo de modelado se destinaron. ¿Para qué tipo de situaciones fueron diseñados los rasgos?

    
pregunta Extrakun 21.03.2016 - 08:27

1 respuesta

4

Los rasgos son otra forma de hacer composición. Piense en ellos como una forma de componer todas las partes de una clase en tiempo de compilación (o tiempo de compilación JIT), ensamblando las implementaciones concretas de las partes que necesitará.

Básicamente, quieres usar rasgos cuando te encuentras haciendo clases con diferentes combinaciones de características. Esta situación se presenta con mayor frecuencia para las personas que escriben bibliotecas flexibles para que otras las consuman. Por ejemplo, aquí está la declaración de una clase de prueba de unidad que escribí recientemente usando ScalaTest :

class TestMyClass
  extends WordSpecLike
  with Matchers
  with MyCustomTrait
  with BeforeAndAfterAll
  with BeforeAndAfterEach
  with ScalaFutures
Los

marcos de prueba de unidad tienen toneladas de diferentes opciones de configuración, y cada equipo tiene diferentes preferencias sobre cómo quieren hacer las cosas. Al poner las opciones en rasgos (que se mezclan al usar with en Scala), ScalaTest puede ofrecer todas esas opciones sin tener que crear nombres de clase como WordSpecLikeWithMatchersAndFutures , o una tonelada de indicadores booleanos en tiempo de ejecución como WordSpecLike(enableFutures, enableMatchers, ...) . Esto facilita seguir el principio de apertura / cierre . Puede agregar nuevas características y nuevas combinaciones de características, simplemente agregando un nuevo rasgo. También hace que sea más fácil seguir el Principio de Segregación de Interfaz , porque puede poner fácilmente funciones que no son universalmente necesarias en un rasgo. / p>

Los rasgos también son una buena manera de poner código común en varias clases que no tienen sentido compartir una jerarquía de herencia. La herencia es una relación muy unida, y no debe pagar ese costo si puede evitarlo. Los rasgos son una relación mucho más débilmente acoplada. En mi ejemplo anterior, utilicé MyCustomTrait para compartir fácilmente una implementación de base de datos simulada entre varias clases de prueba que de otra manera no están relacionadas.

La inyección de dependencia logra muchos de los mismos objetivos, pero en tiempo de ejecución basado en la entrada del usuario en lugar de en el tiempo de compilación basado en la entrada del programador. Los rasgos también se destinan más a dependencias que son semánticamente parte de la misma clase. Usted está reuniendo las partes de una clase en lugar de llamar a otras clases con otras responsabilidades.

La inyección de dependencia frameworks logra muchos de los mismos objetivos en tiempo de compilación en base a la información del programador, pero es en gran medida una solución alternativa para los lenguajes de programación sin el soporte adecuado de rasgos. Los rasgos traen estas dependencias al ámbito del verificador de tipos del compilador, con una sintaxis más clara, con un proceso de compilación más simple, que hace una distinción más clara entre las dependencias en tiempo de compilación y en tiempo de ejecución.

    
respondido por el Karl Bielefeldt 21.03.2016 - 19:35

Lea otras preguntas en las etiquetas