Este artículo proviene de un motor de traducción automática.

El programador políglota

.NET multiparadigmático, Parte II

Ted Neward

En mi artículo anterior (msdn.microsoft.com/magazine/ff955611 de ), la primera de esta serie, mencioné que los dos lenguajes centrales a Microsoft .NET Framework, C# y Visual Basic: multiparadigm estos lenguajes, como C++, sus sintáctica (en el caso de C#) o conceptual (en el caso de Visual Basic) predecesora. Mediante un lenguaje multiparadigmatic puede ser confuso y difícil, especialmente cuando no claro lo que respecta los paradigmas diferentes.

Similitudes y variabilidad

Pero antes de que se puede iniciar teniendo sentido los paradigmas diferentes en estos idiomas, una pregunta más grande que se refiere a la cuenta: ¿Lo, exactamente, nos hemos intentando hacer cuando se diseña un sistema de software? Olvidar los objetivos “ Finalizar resultados ”: modularidad, extensibilidad, simplicidad y todos los que jazz: para un momento y enfoque más en “ cómo ” del lenguaje. ¿Cómo, exactamente, estamos intentar crear todos estos objetivos “ obteniéndose ”?

O de Juan. Coplien, desde su “ Multi-Paradigm diseño de C++ ” (Addison-Wesley Professional, 1998), tiene una respuesta para nosotros:

Cuando pensamos abstractly, se destacar lo que es común al suprimir el detalle. Una abstracción de buen software requiere que entendemos el problema lo suficientemente bien como en toda su amplitud saber lo que es común a través de los elementos relacionados de interés y saber qué detalles varían de un elemento a otro. Los elementos de interés se denominan colectivamente una familia y las familias, en lugar de las aplicaciones individuales, son el ámbito de la arquitectura y diseño. Podemos utilizar el modelo de similitudes y variabilidad independientemente de si los miembros de la familia son módulos, clases, funciones, procesos o tipos;funciona para cualquier paradigma. Similitudes y variabilidad están en el centro de la mayoría de las técnicas de diseño.

Piense en el modelo de objeto tradicional durante unos instantes. Como desarrolladores orientados a objetos, se nos enseñan de desde el principio “ identificar los nombres ” del sistema y busque errores en los que se componen de una entidad determinada, para buscar todas las cosas que pertenecen a la que se va a un profesor “ ” dentro del sistema, por ejemplo y colocarlos en una clase denominada profesor. Pero si demuestran de varios “ sustantivos ” comportamiento superpuesto y relacionado, como, por ejemplo, un alumno “ ” tener algunos datos y las operaciones se superponen con una persona “ ” pero con algunas diferencias de marcado:, a continuación, nos estamos enseñados que en su lugar de duplicar el código común, se debe elevar la uniformidad en una clase base y se relacionan con los tipos entre sí a través de herencia. En otras palabras, su compatibilidad se agrupan dentro de una clase, y cambios en la que se capturaron mediante la ampliación de esa clase y la presentación de las variaciones. Al encontrar y expresar las similitudes y variaciones que existen dentro de un sistema, se llega al corazón del diseño.

Similitudes con frecuencia son las partes que son difíciles de identificar de forma explícita, no porque no somos conscientes de ellos, pero debido a que sean tan fácilmente y reconocible de forma intuitiva resulta difícil detectarlos. ¿Por ejemplo, si digo, “ Vehicle ”, qué imagen se muestra en el encabezado? Si lo hacemos en este ejercicio con un grupo de personas, cada uno tendrá una imagen diferente, aunque haya gran compatibilidad entre todos ellos. Sin embargo, si se empieza a enumerar los diversos vehículos imaginados, los distintos tipos de variaciones comenzarán surgen y categorizar a sí mismos (esperamos), de modo que aún podemos tenemos algún conjunto de similitudes entre los vehículos.

Positivo y negativa de la variabilidad

Variabilidad puede proceder de dos formas básicas, uno de los cuales es fácil de reconocer y otros mucho más difícil. Variabilidad positiva es cuando la variabilidad en forma de agregar a la compatibilidad básica. Por ejemplo, imagínese la abstracción que se desea que el de un mensaje, como, por ejemplo, un mensaje SOAP o correo electrónico. Si decidimos que tiene un encabezado y cuerpo de un tipo de mensaje y deje de distintos tipos de fin de utilizar que como el punto en común, a continuación, una variabilidad positiva de esto es un mensaje que lleva a un valor determinado en su encabezado, tal vez la fecha y hora que se envió. Esto suele ser fácilmente se captura en construcciones de lenguaje, en el paradigma orientado a objetos, por ejemplo, es relativamente muy fácil de crear una subclase de mensajes que agrega compatibilidad con la fecha/hora de envío.

Cambios en negativo, sin embargo, es mucho más complicado. Tal como se deduce que, una variabilidad negativa quita o se contradice de algún aspecto de los factores comunes, un mensaje que tiene un encabezado, pero sin cuerpo (por ejemplo, un mensaje de confirmación que se utiliza la infraestructura de mensajería) es una forma de variabilidad negativa. Y, como probablemente ya se puede suponer, esto se captura en una construcción de lenguaje es problemática, en C# y Visual Basic tiene una utilidad para quitar un miembro declarado en una clase base. Lo mejor que podemos hacer en este caso es el valor devuelto nulo o no hay nada del elemento Body, que se reproducirá claramente un caos con cualquier código que espera un cuerpo está presente, tales como rutinas de comprobación que se ejecutan un CRC en el cuerpo para asegurarse de que se transmitió correctamente.

(Curiosamente, tipos de esquemas XML ofrecen la variabilidad negativa en sus definiciones de esquema de validación, algo que no estándar lenguaje pero ofertas de programación, que es una de las formas que la definición de esquemas XML puede discrepancia en lenguajes de programación. Si se convertirá en una característica futura de algún lenguaje de programación como-y-implícita, y si sería una buena Thing A utilizar, es una discusión interesante mejor tenían a través de la cerveza.)

En muchos sistemas, variabilidad negativa se utiliza normalmente con construcciones de código explícito en el nivel de cliente, lo que significa es que los usuarios del tipo de mensaje para realizar algunas de if/else prueba para ver qué tipo de mensaje está antes de examinar el cuerpo, que representa el trabajo que se coloque en la familia de mensaje prácticamente irrelevante. Demasiados cambios en negativo el diseño de secuencias de escape suele ser la causa subyacente de las llamadas de los desarrolladores a “ todo de tono y empezar de nuevo.

La uniformidad de enlace y de los cambios

En este momento real que se establecen similitudes y variabilidad varía con cada paradigma y en general, cuanto más cerca para que se ejecute el momento en que podemos enlazar esas decisiones, el control que más se ofrecen a los clientes y los usuarios a través de la evolución del sistema y su conjunto. Cuando se habla de un paradigma determinado o técnica dentro de un paradigma, es importante reconocer en cuál de las siguientes cuatro “ tiempos de enlace ” se activa la variabilidad entre:

  1. Hora de origen. Éste es el tiempo que antes de que se activa el compilador hacia arriba, cuando el desarrollador (o alguna otra entidad) es crear los archivos de origen que va al final se alimenta el compilador. Código-generative técnicas, como, por ejemplo, el motor de plantillas de T4 y en menor medida el sistema ASP.NET: funcionan en un enlace en tiempo de origen.
  2. Tiempo de compilación. Como su nombre indica, este enlace se produce durante la pasada del compilador sobre el código fuente para procesarlo en instrucciones ejecutables de la CPU o de código compilado de bytes. Una gran cantidad de toma de decisiones se finaliza en este caso, aunque no todos, como veremos.
  3. Tiempo de vínculo o carga. En el momento en que se carga el programa y se ejecuta, un punto adicional de variabilidad comienza en, en función de los módulos específicos (conjuntos, en el caso de. NET;Archivos DLL, en el caso de código nativo de Windows) que se cargan. Esto es comúnmente como arquitectura plug - in o agregar-de-estilo cuando se aplica a un nivel de escala de todo sistema.
  4. Tiempo de ejecución. Durante la ejecución del programa, se pueden capturar ciertas variaciones en función de la entrada del usuario y la decisión código potencialmente diferente y que ejecuta (o incluso genera) se basa en las decisiones y entrada.

En algunos casos, el proceso de diseño desea iniciar desde estos “ enlazar veces ” y con versiones anteriores para averiguar qué idioma se construye el trabajo puede admitir el requisito.Por ejemplo, un usuario que desee tener la posibilidad de agregar o quitar/modificar variabilidad en la ejecución de tiempo (de modo que no tenemos que volver a través de un ciclo de compilación o volver a cargar el código), lo que significa que el paradigma que utiliza el diseñador, debe ser compatible con un enlace de variabilidad en tiempo de ejecución.

Desafío

En mi artículo anterior, dejé los lectores con una pregunta:

Como ejercicio, tenga en cuenta esto: .NET Framework 2.0 introduce genéricos (tipos parametrizados). ¿Por qué? Desde una perspectiva de diseño, ¿qué finalidad que sirven? (Y el registro, las respuestas de “ IT nos permite disponer de colecciones de tipos ” falta el punto, Windows Communication Foundation utiliza los componentes genéricos en gran medida, claramente de modo que no es sólo de los tipos colecciones.)

Teniendo esto un poco más, observe la implementación (parcial) de una clase Point en 1 de la figura , que representa una cartesiana X coordenadas de punto Y, al igual que los píxeles en una pantalla o en un gráfico más clásico.

La figura 1 la implementación parcial de una clase Point

Public Class Point
  Public Sub New(ByVal XX As Integer, ByVal YY As Integer)
    Me.X = XX
    Me.y = YY
  End Sub

  Public Property X() As Integer
  Public Property y() As Integer

  Public Function Distance(ByVal other As Point) As Double
    Dim XDiff = Me.X - other.X
    Dim YDiff = Me.y - other.y
    Return System.Math.Sqrt((XDiff * XDiff) + (YDiff * YDiff))
  End Function

  Public Overrides Function Equals(ByVal obj As Object) As Boolean
    ' Are these the same type?
If Me.GetType() = obj.GetType() Then
      Dim other As Point = obj
      Return other.X = Me.X And other.y = Me.y
    End If
    Return False
  End Function

  Public Overrides Function ToString() As String
    Return String.Format("({0},{1}", Me.X, Me.y)
  End Function

End Class

En y por sí misma, no es realmente todo lo que interesantes. El resto de la implementación es de izquierda a la imaginación del lector, ya que no es fundamental para la discusión.

Tenga en cuenta que esta implementación de punto se realizado algunas suposiciones acerca de la forma se supone que se utilizan puntos. Por ejemplo, los elementos de X e Y del punto de son números enteros, lo que significa que esta clase de punto no puede representar puntos decimales, como puntos en (0,5,0,5). Inicialmente, esto puede ser una decisión aceptable, pero inevitablemente, aparecerá una solicitud hasta que se le pregunta si desea ser capaz de representar “ puntos fraccionarios ” (por cualquier motivo). Ahora, el desarrollador tiene un problema interesante: ¿Cómo representar este nuevo requisito?

A partir de los conceptos básicos, let’s lo “ OH señor no lo haga ” simplemente crear una nueva clase Point que utilice a los miembros de punto flotante en vez de miembros integrales y vea lo que surge (consulte la figura 2 de ;Tenga en cuenta que PointD siglas “ Point-doble, ” lo que significa que utiliza dobles). Ya que es bastante desactive, hay una gran cantidad de conceptos superposición entre los dos tipos de punto. Con arreglo a la teoría de similitudes y variabilidad de diseño, que significa que necesitamos para capturar las piezas comunes y permitir la variabilidad de alguna manera. Orientación a objetos de clásico nos sería necesario hacerlo a través de herencia, elevar la uniformidad en una clase o interfaz base (punto) y, después, en que la implementación en subclases (PointI y PointD, tal vez).

La figura 2 de Una nueva clase Point con miembros de punto flotante

Public Class PointD
  Public Sub New(ByVal XX As Double, ByVal YY As Double)
    Me.X = XX
    Me.y = YY
  End Sub

  Public Property X() As Double
  Public Property y() As Double

  Public Function Distance(ByVal other As Point) As Double
    Dim XDiff = Me.X - other.X
    Dim YDiff = Me.y - other.y
    Return System.Math.Sqrt((XDiff * XDiff) + (YDiff * YDiff))
  End Function

  Public Overrides Function Equals(ByVal obj As Object) As Boolean
    ' Are these the same type?
If Me.GetType() = obj.GetType() Then
      Dim other As PointD = obj
      Return other.X = Me.X And other.y = Me.y
    End If
    Return False
  End Function

  Public Overrides Function ToString() As String
    Return String.Format("({0},{1}", Me.X, Me.y)
  End Function

End Class

Interesantes problemas surgen de esto, sin embargo el intento. En primer lugar, las propiedades X e Y necesitan un tipo asociado, pero la variabilidad entre las dos preocupaciones de subclases diferentes cómo se almacenan las coordenadas X e Y y, por tanto, representa a los usuarios. El diseñador siempre simplemente se puede optar por la representación más grande o más ancha o más completa, que en este caso sería un valor de tipo Double, pero por lo que significa que tiene un punto de que sólo puede tener los valores de tipo Integer es ahora perdido como una opción y deshace todo el trabajo de la herencia se ha diseñado para permitir. Además, debido a está relacionado con la herencia ahora, las dos implementaciones de punto de heredar ahora son supuestamente intercambiables, por lo que se debe ser capaces de pasar un PointD a un método PointI distancia, que puede o no puede ser conveniente. ¿Y es un PointD de (0.0, 0.0) equivalente (como en es igual A) a un PointI de (0,0)? Todas estas cuestiones deben tenerse en cuenta.

Aunque estos problemas se fija o realizados tractable de alguna manera, surjan otros problemas. Más adelante, queremos posible que sea un punto que acepte los valores mayores que se pueden almacenar en un valor de tipo Integer. O los valores de positivos sólo absoluto (es decir, el origen está en la esquina inferior izquierda) se consideran aceptables. Cada uno de estos requisitos diferentes, significará que se deben crear un nuevas subclases de un punto.

Ejecución paso a paso hacia atrás por un momento, el deseo original era reutilizar la uniformidad de la implementación de punto y permitir de variabilidad en la representación de tipo o de los valores que componen el punto. En el ideal, según el tipo de gráfico que estamos trabajando con, se debe poder elegir la representación en el momento de de que crea el punto y podría representar a sí mismo como un tipo totalmente distinto y diferente, que es precisamente lo que los componentes genéricos.

Sin embargo, al hacerlo, representa un problema: El compilador insiste en que los tipos de “ representante ” no tienen necesariamente “ + ” y “-” operadores definidos para él, porque piensa que desea incluir cualquier tipo posible aquí, enteros, valores extensos, cadenas, botones, DatabaseConnections o cualquier otra cosa que le ocurra, y que es claramente un poco demasiado variable. Por lo tanto, una vez más, es necesario expresar algunos factores comunes para el tipo que se puede utilizar a continuación, en forma de una restricción de genérica en los tipos “ representante ” puede ser (consulte de figura 3).

La figura 3 de una restricción genérica de tipo

Public Class GPoint(Of Rep As {IComparable, IConvertible})
  Public Sub New(ByVal XX As Rep, ByVal YY As Rep)
    Me.X = XX
    Me.Y = YY
  End Sub

  Public Property X() As Rep
  Public Property Y() As Rep

  Public Function Distance(ByVal other As GPoint(Of Rep)) As Double
    Dim XDiff = (Me.X.ToDouble(Nothing)) - (other.X.ToDouble(Nothing))
    Dim YDiff = (Me.Y.ToDouble(Nothing)) - (other.Y.ToDouble(Nothing))
    Return System.Math.Sqrt((XDiff * XDiff) + (YDiff * YDiff))
  End Function

  Public Overrides Function Equals(ByVal obj As Object) As Boolean
    ' Are these the same type?
If Me.GetType() = obj.GetType() Then
      Dim other As GPoint(Of Rep) = obj
      Return (other.X.CompareTo(Me.X) = 0) And (other.y.CompareTo(Me.Y) = 0)
    End If
    Return False
  End Function

  Public Overrides Function ToString() As String
    Return String.Format("({0},{1}", Me.X, Me.Y)
  End Function

End Class

En este caso, se imponen dos restricciones: uno para asegurarse de que se puede convertir cualquier tipo “ representante ” a valores double (para calcular la distancia entre los dos puntos) y otro para asegurarse de que el componente X y valores Y se pueden comparar para ver si son mayor que/igual-a o menor-que entre sí.

Y ahora queda más claro el motivo de los componentes genéricos: son compatibles con un “ eje ” diferente de los cambios de diseño, que es considerablemente diferente desde el eje basado en herencia tradicional. Permite que el diseñador representar la implementación como similitudes y los tipos que se está operando en la implementación sea variaciones.

Tenga en cuenta que esta implementación se supone que se está produciendo la variabilidad en tiempo de compilación, en lugar de en tiempo de carga/vínculo o tiempo de ejecución, si el usuario quiere o necesita especificar el tipo de X y se necesita Y de los miembros de los puntos en tiempo de ejecución, a continuación, en una solución diferente.

No responde (o no listo) todavía.

Si todo el diseño de software es un ejercicio de gigante en similitudes y variabilidad, a continuación, la necesidad de entender el diseño multiparadigmatic queda clara: Cada uno de los paradigmas diferentes ofrece distintas formas de lograr este similitudes y variabilidad y los paradigmas de mezcla crea confusión y da lugar a las llamadas para la reescritura completa. Como el cerebro humano comienza a confundirse cuando se intenta asignar construcciones tridimensionales en la cabeza en las dimensiones de cuatro y cinco, demasiadas dimensiones de variabilidad en el software de confusión.

En los artículos siguientes half-dozen o es así, podrá estar buscando en las distintas formas que admite cada paradigma de C# y Visual Basic, los paradigmas de estructurales, orientado a objetos, metaprogramación, funcionales y dinámicos que se va a las entidades de seguridad, proporcionan funcionalidad para capturar la uniformidad y permite la variabilidad. Cuando estamos a través de todo eso, examinaremos cómo algunas de ellas pueden combinarse en formas interesantes para hacer más cosas de modular, extensible, fácil de mantener y todo lo que otros de los diseños.

¡ Feliz codificación!

Ted Neward is a principal with Neward & Associates, an independent firm specializing in enterprise .NET Framework and Java platform systems. Ha escrito más de 100 artículos, es un ponente de MVP de C# y de INETA y ha creado y coautor de libros de una docena, como “ Professional F # 2.0 ” (Wrox, 2010). También consulta y mentors con regularidad. Ponerse en ted@tedneward.com con preguntas o solicitudes de consultoría y leer su blog en blogs.tedneward.comde .

Gracias al siguiente experto técnico para este artículo: Anthony verde