loading...

miércoles, 18 de agosto de 2010

En el primer enfoque, características Scala similares a las interfaces (como se define Java). Salvo que sólo una interfaz declarar métodos, mientras que una línea tiene la posibilidad de implementar y para declarar Miembros de datos.

Rasgos Scala y decoradores

Fecha de publicación : 15/08/2010

Por Sylvain Leroux ( Inicio ) ( About Me)

 

En el primer enfoque, características Scala similares a las interfaces (como se define Java). Salvo que sólo una interfaz declarar métodos, mientras que una línea tiene la posibilidad de implementar y para declarar Miembros de datos.
Pero su uso es muy superior al de una interfaz mejorada. Así, en este artículo, vamos a ver cómo es posible combinar las características de una clase a desarrollar comportamientos específicos.
En este artículo se asume un conocimiento básico de la sintaxis de la Scala.



Viadeo Gorjeo Google Bookmarks ! Facebook Digg del.icio.us MySpace Yahoo MyWeb Blinklist Netvouz Reddit Simpy StumbleUpon Marcadores Windows Live Favorites      






I. Introducción

II. En el paquete

III. Ofertas modulares

III -A. Herencia simple

III -B. Decorador

III -C. Características

III- C-1. estupendo y linealización

III- C -2. Mezclar varias características

III-D . Informe mixins

IV. ¿Qué rasgos ...

V. Conclusión

VI. Recursos

VII. Gracias






I. Introducción

Para este artículo , se procederá a partir de un caso muy simple, poco a poco iremos complicados para ver qué opciones están disponibles para implementar una solución en la Scala.



El ejemplo que servirá como ejemplo aquí es el de una suscripción de software de facturación telefónica . forma rudimentaria , cada cuenta es un objeto con un método para imputar una comunicación:
Compte.scala


/ **
 * Un cuenta de facturación teléfono.
 *
clase Cuenta( Atención al cliente : Cadena) (
  / **
   * El número de segundo consumidos (a cargo) esta mes-Esta.
   *
  var tempsConsomme = 0
  / **
   * Declaración de Comunicaciones cargado.
   *
  var notas = Nuevo ArrayBuffer [ Tuple3 [Cadena,Int,Int] ] ()
 
  / **
   * Imputa una comunicación en esta cuenta.
   *
  def imputa( Segundos Int, El beneficiario : Cadena) Unidad = (
    tempsConsomme += segundo
    notas.anexar(( Receptor, segundo , tempsConsomme ))
  )
 
  anular def toString( ) Cadena = (
    val resultado = Nuevo StringBuilder( )
 
    resultado.anexar("% -10s :".formato( Cliente))
    releve.foreach ( t => resultado.anexar("N \% 5D % % t -14 5d %".formato( T._1 , t._2 , t._3 )) )
    resultado.anexar("% N% n \ t s".formato("-"*25) )
    resultado.anexar("N \% 19s % t 5d %".formato("Total :", TempsConsomme ))
 
    resultado.toString( )
  )
)
Podríamos asegurar el funcionamiento de una cuenta con el programa de pruebas siguientes :
Chapitre_I.scala


objeto Chapitre_I (
  def mano(Args : [ ArrayCadena]): Unidad = (
 
    val Clientes = Conjunto(
      Nuevo Cuenta("george")
    )
 
    clients.foreach ( cuenta =>
       / * Créditos 5 Comunicaciones de 10 120 y 900 segundo a cada cuenta *
       (0 Hasta 5) . Foreach ( n =>
        cuenta.imputa(10, "888")            / / 10 segundo a contestador automático  
        cuenta.imputa(2*60, "888")          / / 2 acta a contestador automático
        cuenta.imputa(15*60, "06xxxxxxxx")  / / 15 acta a una portátil 
        )
 
        println(Cuenta )
    )    
  )
)
Si lanza la demo podrás obtener el siguiente resultado:


george :
10 de octubre 888
888.120.130
06xxxxxxxx 900 1030
888 10 1040
888 120 1160
06xxxxxxxx 900 2060
888 10 2070
888 120 2190
06xxxxxxxx 900 3090
888 10 3100
888 120 3220
06xxxxxxxx 900 4120
888 10 4130
888 120 4250
06xxxxxxxx 900 5150
-------------------------
Total : 5150
Bien, nada muy emocionante en el momento . A lo sumo , podemos asegurar que las llamadas se están contando en el segundo. Pero sabes , no es como funciona todas las suscripciones de teléfono ...





II. En el paquete

Hasta ahora , hemos introducido un segundo de facturación . Pero muy a menudo el usuario opta por un paquete . Como el código de nuestra aplicación como un hecho Juan tiene un paquete de "2:00"? La manera más fácil sería crear un nuevo tipo de cuenta . La reacción aquí sería la de utilizar ellegado:
Forfait.scala


/ **
 * Un Paquete.
 * 
 * Cuenta en que una crédito de comunicación es pradera-cargado.
 *
clase Paquete( Atención al cliente : Cadena, Crédito : Int) se extiende Cuenta(Cliente) (
  / **
   * Crédito restantes en el Paquete
   *
  var restantes = Crédito
  
 
  / / proyecto de ley inmediatamente el consumo previsto en el Paquete
  gran.imputa( crédito , "** Paquete **")
 
  anular def imputa( Segundos Int, El beneficiario : Cadena) Unidad = (
    restantes -= segundo
    si ( Resto de < 0) (
      / / fuera paquete!
      gran.imputa(-restantes receptor)
      restantes = 0
    )
  )
 
  anular def toString( ) Cadena = (
    "% S ( Resto de en Paquete: D%)".formato(gran.toString(), restante )
  )
)
No es difícil de modificar el programa de pruebas para tener en cuenta un nuevo cliente con un paquete:
Chapitre_II.scala


/ / ...
 val Clientes = Conjunto(
  Nuevo Cuenta("george")
  Nuevo Paquete("Juan",2*60*60) / / Paquete 2 horas
 )
/ / ...
Por último, la aplicación nos da el resultado esperado:

george :
10 de octubre 888
888.120.130
06xxxxxxxx 900 1030
888 10 1040
888 120 1160
06xxxxxxxx 900 2060
888 10 2070
888 120 2190
06xxxxxxxx 900 3090
888 10 3100
888 120 3220
06xxxxxxxx 900 4120
888 10 4130
888 120 4250
06xxxxxxxx 900 5150
-------------------------
Total : 5150
john :
** ** Paquete 7200 7200
-------------------------
Total : 7200 ( resto del paquete : 2050)
   
Una vez más , nada extraordinario . Y nada específico a Scala es la programación orientada a objetos todo lo que hay desde las más clásicas . Ha llegado el momento de complicar el ejemplo un poco ...





III. Ofertas modulares

Los operadores de telefonía no son personas que pueden estar satisfechos con dos ofertas . Por lo tanto, para la felicidad de sus clientes , les gusta que les ofrecen una variedad de opciones. Tal como el libre acceso a sus servicios (voz , seguido por el consuelo , ...). Y, por supuesto , esta opción debería aplicarse a diferentes tipos de suscripciones. Esto ahora nos da cuatro posibles acuerdos :




  1. Facturación por segundos ;

  2. de facturación de paquetes ;

  3. de facturación en segundo lugar con el libre acceso a los servicios de operador ;

  4. de facturación de paquetes con acceso gratuito a los servicios del operador.
Así , la forma de codificar esta en Scala ? Eso es lo que consideraremos más adelante en este artículo , teniendo en cuenta , sucesivamente, varias opciones disponibles : en primer lugar , vamos a continuar con el impulso al considerar una solución basada en elherencia simple. Luego se discute la Decorador de patrón de diseño. Y, por último , llegamos a la conclusión al ver cómo Scala proporciona el nivel de idioma con una alternativa características.





III -A. Herencia simple

Para empezar , considere la posibilidad de utilizar elherencia simple el modelo de todas estas diferentes ofertas. Después de todo , esta solución parece satisfactoria a la introducción de Paquete. Así que ¿por qué cambiar una solución que funciona ?



Como se observa en el diagrama UML anterior, agregue una única opción implica la creación de dos nuevas clases : una para los paquetes, uno para las cuentas . Ni que decir tiene que el código puede ser en gran medida redundante. Por otra parte, más allá de este ejemplo, no es difícil darse cuenta con esta solución la multiplicación de opciones conducirá a una explosión combinatoria del número de clases para ser codificado en el sistema. En resumen , esta solución conduce rápidamente a una pesadilla de mantenimiento. Este es probablemente el momento de apelar a Banda de los cuatro para ver lo que ofrecen ...





III -B. Decorador

La solución tradicional a este problema es el uso de Decorador de patrón de diseño. Con este modelo, la lógica específica de cada opción ya no está para ser codificado una vez. Y se puede utilizar para decorar cualquier autoridad de CompteAbstrait . Finalmente, una cuenta ya decoradas , que permite la combinación.



Una aplicación sería la siguiente :
DecorateurServicesGratuits.scala

/ **
 * Un clase que pone en trabajo el libre de s'acceso a 
 * servicios de s'operador.
 * 
 * Esta decorador puede s'aplicar a n'importante qué CompteAbstrait.
 *
clase DecorateurServicesGratuits(Base: CompteAbstrait ) se extiende CompteAbstrait (
  anular def imputa( Segundos Int, El beneficiario : Cadena) Unidad = (
    val servicesCompris = Conjunto("888", "750", "751")
 
    / / si el destinatario no hecho no partido de servicios libre imputar
    si (!servicesCompris .contiene( Receptor ))
      base .imputa(Segundos , el receptor )
  )
 
  anular def toString( ) = (
    base .toString( )
  )
)
Chapitre_III_B.scala

/ / ...
    val Clientes = Conjunto(
      Nuevo Cuenta("george")
      Nuevo DecorateurServicesGratuits(Nuevo Paquete("Juan",2*60*60) ) / / Paquete 2 horas
      Nuevo DecorateurServicesGratuits(Nuevo Cuenta("paul") )
    )
/ / ...
El diseñador puede cambiar Dinámicamente el comportamiento de un objeto durante la ejecución. Además, la aplicación de una interfaz común permite a los diseñadores para reemplazar el objeto que decora . Es esta característica que les permite combinar. Por supuesto , esto implica que el diseñador implementa todos los métodos empleados tanto del objeto detrás de ella - por lo menos como talones de que simplemente pasar el control al objeto de base. Este es el caso en el ejemplo anterior de la toString ().



Aunque posiblemente tedioso , no es un problema en el caso de la clase abstracta contiene la raíz de todos los métodos necesarios. Pero de todos modos , esto puede suponer un problema. Consideremos el caso de los paquetes con los servicios gratuitos :

Nuevo DecorateurServicesGratuits(Nuevo Paquete("Juan",2*60*60) )
El DecorateurServicesGratuits objeto creado y puede ser utilizado como un CompteAbstrait - porque bajo el legado es un CompteAbstrait . Por contra, los métodos y las propiedades específicas del paquete ya no son accesibles desde el exterior.



Este problema es más probable que ocurra cuando usted adorna un objeto que implementa varios interfaces. Sólo las interfaces de aplicación efectiva en el diseñador puede manipular el objeto. En la siguiente ilustración , el uso de decorador ServicesGratuits limita los métodos disponibles en elOffre3G las de la interfaz CompteAbstrait. Estos interfaz AccesInternet ya no son accesibles , aunque implementado por el objeto concreto .



En otras palabras , un diseñador no respeta el principio de sustitución de Liskov : un decorador no puede utilizarse, cuando el objeto decorado puede ser.



De alguna manera, el diseñador tiene las desventajas de sus ventajas : está diseñado para cambiar dinámicamente el comportamiento de la ejecución de una objeto. No para crear de forma estática durante la compilación nueva tipos. Sin embargo, eso es precisamente lo que permite a las características de Scala ...





III -C. Características

Scala nos ofrece la oportunidad crear nuevos tipos de compilación la combinación de los métodos y los miembros de datos de una clase con los de uno o más características. En la terminología de las clases Scala que se construyen de esta forma se llaman mixins.



La notación utilizada para crear mixins utilizando la palabra clave con como en el ejemplo siguiente. Quisiera llamar su atención sobre el hecho de que el rasgo puede ser ServicesGratuits mixto Cuenta , o un paquete :
Chapitre_III_C.scala

/ / ...
    val Clientes = Conjunto(
      Nuevo Cuenta("george")
      Nuevo Paquete("Juan",2*60*60) con ServicesGratuits , / / Paquete 2 horas con servicios Libre
      Nuevo Cuenta("paul") con ServicesGratuits           / / cuenta con servicios Libre
    )
/ / ...
La diferencia fundamental con el modelo de diseño decorador se ilustra en el diagrama UML arriba: se puede ver que relaciones sólo la herencia están presentes. Por lo tanto, un paquete con libre es un paquete. Eso todavía una mixin se puede utilizar siempre que sea una instancia deuna de sus clases base oUna característica mixta puede ser.



Si en este punto hemos detallado losuso un derrame cerebral, aún no hemos visto cómo los definir. Con el código de abajo se va a hacer . Como se ve , la definición de un rasgo es muy similar a una clase. La única diferencia evidente es el uso de la palabra clave línea en lugar de clase:
ServicesGratuits.scala


/ **
 * Un línea que pone en trabajo el libre de s'acceso a 
 * servicios de s'operador.
 * 
 * El línea ServicesGratuits no puede s'aplicar que'a una Cuenta.
 *
línea ServicesGratuits se extiende Cuenta (
  anular def imputa( Segundos Int, El beneficiario : Cadena) Unidad = (
    val servicesCompris = Conjunto("888", "750", "751")
 
    / / si el destinatario no hecho no partido de servicios libre imputar
    si (!servicesCompris .contiene( Receptor ))
      gran.imputa(Segundos , el receptor )
  )
)
Tenga en cuenta que la línea ServicesGratuits se extiende clase de cuenta . Pero para un accidente cerebrovascular , esta afirmación es más bien una declaración restricción: un rasgo se puede mezclar con su clase base o una clase derivada de ella. El corolario es queuna clase no puede ser combinada con una línea directa cuya matriz se encuentra en su jerarquía de elementos primarios.



Esta limitación significa que la semántica de la relación de herencia se mantiene en el nivel de objeto . De hecho, desde ServicesGratuits se puede mezclar con la cuenta o cualquiera de sus clases derivadas , se puede decir con certeza que cualquier instancia de mezcla ServicesGratuits es una instancia de la cuenta .



Es imposible mezclar el ServicesGratuits línea para alojamiento de primera clase si no es una subclase de la cuenta .
Más sutil aún , el aviso en el código de la llamada función super.impute:
ServicesGratuits.scala

línea ServicesGratuits se extiende Cuenta (
  anular def imputa( Segundos Int, El beneficiario : Cadena) Unidad = (
    / / ...
      gran.imputa(Segundos , el receptor )
  )
...
En el contexto de una clase, esta notación significa " llamar al método establecido en las clase base. Pero necesariamente en el caso de una línea! De hecho , cuando la definición de la línea, Scala no sabe todavía cómo va a ser mezclado clase. Por lo tanto , la clase de referencia gran se resuelve en tiempo de compilación de mixin. Por otra parte, un mixin el otro una referencia a la super en el mismo rasgo no necesariamente hará referencia a un mismo ancestro .



¿Y cómo Scala determina la clase de referencia super ? Usando una técnica llamada linealización haremos a continuación.





III- C-1. estupendo y linealización

El punto es entender que con la introducción de características, la gráfica de herencia ( implementación) no es necesariamente un árbol como lo es en Java. Para determinar qué clase o rasgo gran hará referencia a la compilación establece Scala cada mixin un orden estricto para las diferentes clases y funciones que lo componen. Es linealización.



Especificaciones de la Scala especificar algoritmo exacto utilizado . Pero al hacer simple, en el orden determinado por la linealización , un mixin está siempre delante de su cara y mezclado antes de su super - clase. Y si una clase o una sola línea aparece varias veces , sólo Pasado caso se conserva . Este último punto en particular los medios que, de acuerdo a la clase con la que un rasgo se mezcla , super no se refiere necesariamente al mismo tipo .



Más concretamente , el orden seleccionado para el mixin Paquete con ServicesGratuits es la siguiente:




  1. Paquete con ServicesGratuits ( la propia mixin ) ;

  2. ServicesGratuits ( accidentes cerebrovasculares son linealizadas antes de la clase base) ;

  3. Paquete (una clase se serializa antes de su super - clase);

  4. Cuenta
En comparación, la resolución de la cuenta con ServicesGratuits mixin es:




  1. En ServicesGratuits con ( el propio mixin )

  2. ServicesGratuits ( accidentes cerebrovasculares son linealizadas antes de la clase base)

  3. Cuenta
mixin Scala linealiza cada uno independientemente . Así, el super.impute llamada en el método ServicesGratuits relacionados invoca en un caso en el Forfait.impute Compte.impute otros . Veremos en la próxima sección que podemos mezclar las características múltiples de forma simultánea y una super también podrá designar a otro derrame cerebral.



III- C -2. Mezclar varias características

Ahora vamos a abordar el corazón de esta técnica: a saber, la posibilidad de combinan varios rasgos en un mixin. Para ilustrar este punto , pulsaremos el caso de Ringo , que recibió un pase " una hora "con el libre acceso a los servicios de operador , pero en el que comunicación con el exterior de la cuenta doble embalaje. Para implementar esta última especificación , de nuevo una característica se puede utilizar :
PenalitesHorsForfait.scala


línea PenalitesHorsForfait se extiende Paquete (
  anular def imputa( Segundos Int, El beneficiario : Cadena) Unidad = (
    si ( Segundos > restante)
      gran.imputa( Segundos-restantes "** Pena **")
 
    gran.imputa(Segundos , el receptor )
  )
)
El PenalitesHorsForfait sólo puede aplicarse a un paquete. Esta es la manera explícita en la declaración:

línea PenalitesHorsForfait se extiende Paquete ( ...
Así que aquí estamos con un usuario cuyo envase debe mezclar dos derrames cerebrales. Esto se escribe como en Scala :
Chapitre_III_C_2.scala

/ / ...
    val Clientes = Conjunto(
      Nuevo Cuenta("george")
      Nuevo Paquete("Juan",2*60*60) con ServicesGratuits , / / Paquete 2 horas
      Nuevo Cuenta("paul") con ServicesGratuits ,
      Nuevo Paquete("Ringo", 1*60*60) con PenalitesHorsForfait con ServicesGratuits
    )
/ / ...
Con dos golpes mezclados con el paquete de clase nuevo a la cuestión del orden en que se invocan los métodos . La regla es simple , las últimas funciones ( a cambio ) son una prioridad. Esto implica que orden de los trazos es importante!



En mi ejemplo, ServicesGratuits.impute PenalitesHorsForfait.impute suceder antes . ¿Cuál es el comportamiento deseado : en nuestra aplicación es conveniente que ServicesGratuits tiene la oportunidad de excluir a cierto sistema de facturación de comunicación antes de que el cálculo de las posibles sanciones que se hace.

george :
10 de octubre 888
888.120.130
06xxxxxxxx 900 1030
888 10 1040
888 120 1160
06xxxxxxxx 900 2060
888 10 2070
888 120 2190
06xxxxxxxx 900 3090
888 10 3100
888 120 3220
06xxxxxxxx 900 4120
888 10 4130
888 120 4250
06xxxxxxxx 900 5150
-------------------------
Totales: 5150
john :
** ** Paquete 7200 7200
-------------------------
Total : 7200 ( resto del paquete : 2700)
paul :
900900 06xxxxxxxx
06xxxxxxxx 900 1800
06xxxxxxxx 900 2700
06xxxxxxxx 900 3600
06xxxxxxxx 900 4500
-------------------------
Total : 4500
Ringo :
** ** Paquete 3600 3600
Pena ** ** 900 4500
06xxxxxxxx 900 5400
-------------------------
Total : 5400 ( resto del paquete : 0)



III-D . Informe mixins

Hasta ahora , hemos características mixtas (con ...) directamente en la instancia de objeto (nueva ...) . Esto no es elegante. Una mejor opción sería la de declarar mixin una vez por todas . Luego, una instancia en caso necesario:
Chapitre_III_D.scala


  / * Declaración de tres nuevo tipos *
  clase OffreALaCarte( Atención al cliente : Cadena) se extiende Cuenta(Cliente) con ServicesGratuits
  clase OffreLiberte( Atención al cliente : Cadena, techo Int) se extiende Paquete(Cliente, techo) con ServicesGratuits
  clase OffrePrimo( Atención al cliente : Cadena, techo Int) se extiende Paquete(Cliente, techo) con PenalitesHorsForfait con ServicesGratuits
Chapitre_III_D.scala

/ / ...
    val Clientes = Conjunto(
      Nuevo Cuenta("george")
      Nuevo OffreLiberte("Juan",2*60*60)
      Nuevo OffreALaCarte("paul")
      Nuevo OffrePrimo("Ringo", 1*60*60)
    )
/ / ...



IV. ¿Qué rasgos ...

En este artículo , utilizamos una solución clásico sobre la base de la herencia simple de avanzar hacia la implementación de características para representar las diferentes opciones gestionados por nuestra aplicación. Para continuar con este espíritu, uno podría estar tentado a transformar clase De paquetes en línea.



Nada nos obliga a hacer . Excepto quizás el deseo de normalizar nuestra solución. Para ser honesto, todo será una oportunidad para mí presentar algunos conceptos adicionales. Pero no anticipar demasiado, y empezar con lo que ya sabemos . A priori para transformar clase De paquetes en línea, Sólo tiene que sustituir la palabra clave clase por línea:

línea Paquete( Atención al cliente : Cadena, Crédito : Int) se extiende Cuenta(Cliente) (
  / / contenido sin cambios por informe a el clase
  / / ...
)
El problema es que el código anterior no es válido el código Scala ! De hecho, si tratas de compilar , obtendrá un mensaje que indica :

características objetos de oro no pueden tener parámetros
A diferencia de una clase, un rasgo no puede tener parámetros. De hecho, una línea no puede tener un constructor . Y menos aún para invocar el constructor de su clase base . En resumen, a la definición de nuestra línea puede observar esta situación :

/ / El constructor implícito de línea no puede no recibir argumento
/ / Y lo no puede no no más pasar de parámetros a constructor de el clase de base
línea Paquete se extiende Cuenta (
  / / ...
)
Esto nos plantea un problema : es necesario para determinar el crédito disponible en el paquete. Afortunadamente , Scala nos ofrece la oportunidad de evitar este problema utilizando valores abstractos. El principio es el mismo que el métodos abstractos como ustedes saben , en otros lenguajes de programación : son informó y se puede utilizado en una clase base . Pero lo harán definido en una clase derivada .



En nuestro caso, la valor lo que necesitamos es el crédito disponible en el paquete. Haremos de este valor un valor abstracto . Y será definido en el mixin:

línea Paquete se extiende Cuenta (
  / / Valor " Resumen " - voluntad ser definido por el mixin
  val Crédito: Int

  / / El resto de código es idéntico
  / **
   * Crédito restantes en el Paquete
   *
  var restantes = Crédito
 
  / / proyecto de ley inmediatamente el consumo previsto en el Paquete
  gran.imputa( crédito , "** Paquete **")
 
  anular def imputa( Segundos Int, El beneficiario : Cadena) Unidad = (
    restantes -= segundo
    si ( Resto de < 0) (
      / / fuera paquete!
      gran.imputa(-restantes receptor)
      restantes = 0
    )
  )
 
  anular def toString( ) Cadena = (
    "% S ( Resto de en Paquete: D%)".formato(gran.toString(), restante )
  )
)
Ahora que nuestra línea tiene un valor abstracto , que deben definirse al crear instancias de una clase de mezcla esta característica:


Nuevo Cuenta("Juan") con Paquete con ServicesGratuits (
    / / Establece el valor resumen para esta autoridad
    val Crédito = 2*60*60
  )
También es posible definir el valor de resumen en el mixin :
Chapitre_IV.scala


  clase OffreLiberte( Atención al cliente : Cadena, techo Int)
    se extiende Cuenta(Cliente)
    con Paquete
    con ServicesGratuits (
    / / Establece el valor resumen a de de parámetro 
    / / de constructor implícito de esta mixin
    val Crédito = techo
  )
  
  / / ...
  
  Nuevo OffreLiberte("Juan", 2*60*60)

...
john :
** ** Paquete 7200 7200
-------------------------
Total : 7200 ( resto del paquete : 2700)
...
Excelente, ¿no? Bueno, no tanto ! Supongamos que modificar nuestro programa un poco por la duración del contrato se expresa en hora en el momento de la creación del mismo. El cambio es trivial:
Chapitre_IV.scala


  / / Ahora el techo es expresó en horas
  clase OffreLiberte( Atención al cliente : Cadena, PlafondEnHeure : Int)
    se extiende Cuenta(Cliente)
    con Paquete
    con ServicesGratuits (
    val Crédito = plafondEnHeure*3600 / / convertido el horas en segundo
  )
  
  / / ...
  
  Nuevo OffreLiberte("Juan", 2) / / Paquete 2 horas

...
john :
** Paquete ** 0 0
900900 06xxxxxxxx
06xxxxxxxx 900 1800
06xxxxxxxx 900 2700
06xxxxxxxx 900 3600
06xxxxxxxx 900 4500
-------------------------
Total : 4500 ( resto del paquete : 0)
...
¿Eh? ¿Qué pasó? Tenga en cuenta , en particular, el valor del paquete Imputados: 0 segundos ! La explicación de este misterio es que cuando el valor abstracto es inicializado por una expresión , se estima después de inicialización de las clases base y las características mixtas. Esto es exactamente lo contrario de lo que ocurre cuando se envía argumentos a un constructor. En este caso, los valores de los argumentos que se evalúan antes el rendimiento de distintos fabricantes. Esto es especialmente complicado, porque como vimos antes, cuando un valor abstracto se inicializa con una constante , el compilador se propaga , lo que esconde este comportamiento.



Si estas explicaciones ayudan a entender lo que pasó, sigue siendo el problema de cómo conseguir el comportamiento deseado ? Una solución es Pre- inicializar valores (en Inglés , se habla de Los primeros definiciones) . En concreto, es mostrar la inicialización de los valores de resumen en una manzana ubicada antes clase base :
Chapitre_IV.scala


  / / Ahora el techo es expresó en horas
  clase OffreLiberte( Atención al cliente : Cadena, PlafondEnHeure : Int)
    se extiende ( / / antes de la inicialización de el valor resumen
      val Crédito = plafondEnHeure*3600
    ) con Cuenta(Cliente) / / excepcionalmente aquí el clase de base es presentó por " Con '
    con Paquete
    con ServicesGratuits

  / / ...
  
  Nuevo OffreLiberte("Juan", 2) / / Paquete 2 horas

...
john :
** ** Paquete 7200 7200
-------------------------
Total : 7200 ( resto del paquete : 2700)
...



V. Conclusión

Bueno, este cuenta con la presentación en forma de apilar comportamiento se ha completado. Hemos visto aquí que los movimientos utilizados para componer una clases modulares. Por supuesto , esta técnica no es una panacea. Tiene sus propias limitaciones. Precisamente por el hecho de que mixins son creados estáticamente en tiempo de compilación . Por lo tanto , es necesario volver a compilar todos los mixins si se agrega un método a una línea. Y no podemos (fácilmente ) crear mixins nueva ejecución. Sin embargo, es una herramienta interesante para hacer que el código modular. Para agregar a su kit de herramientas si está programando en Scala !





VI. Recursos



VII. Gracias

Un gran agradecimiento a Eric Siber para mí se propone acoger artículos en Developpez.com y reinterpretaciones de este artículo. En Damien Guichard por su interés en la Scala. También Jacques Thery por su ojo de águila me ha ahorrado un montón de conchas !
http://sylvain-leroux.developpez.com/scala/traits-scala-et-decorateurs/

No hay comentarios:

Publicar un comentario