03/10/2010
Ted Neward
En mi artículo anterior (msdn.microsoft.com/magazine/ff955611), el primero de esta serie, he mencionado que los dos idiomas de la central de Microsoft. NET Framework, C # y Visual Basic, son lenguajes multiparadigma, al igual que C + +, su sintáctica (en el caso de C #), o (en el caso de Visual Basic) predecesora conceptual. El uso de un lenguaje Multiparadigmático, puede ser confuso y difícil, sobre todo cuando los efectos de los diferentes paradigmas no están claros.
Comunalidad y la variabilidad
Pero antes de que podamos empezar a desmontar los paradigmas diferentes, en estas lenguas, una pregunta más grande viene a la mente: ¿Cuál es, precisamente, estamos tratando de hacer cuando se diseña un sistema de software? Olvida el "resultado final" de goles en la modularidad, sencillez de extensibilidad, y todo lo que el jazz-por un momento, y centrarse más en el "cómo" de la lengua. ¿Cómo, exactamente, estamos tratando de crear todos los "resultado final" objetivos?
James O. Coplien, en su "Multi-Paradigma de diseño para C + +" (Addison-Wesley Professional, 1998), tiene una respuesta para nosotros:
Cuando pensamos abstractamente, hacemos hincapié en lo que es común, mientras tenemos la supresión de los detalles. Una abstracción de un buen software requiere que entendamos el problema, lo suficiente con en toda su amplitud, a saber, lo que es común a través de los artículos relacionados de interés y saber lo que los detalles varían de una a otra partida. Puede que los elementos de interés son llamados colectivamente una familia, y las familias, en lugar de aplicaciones individuales, son el ámbito de la arquitectura y el diseño. Podemos usar el carácter común /, como modelo de variabilidad, independientemente de si son miembros de la familia de módulos, clases, funciones, procesos y tipos, que funciona con cualquier paradigma. La comunalidad y la variabilidad, están en el centro de las técnicas de diseño más.
Piense en el paradigma de objetos tradicionales, por un momento. Como desarrollador orientado a objetos, se nos enseña desde el principio a "identificar los sustantivos", en el sistema y buscar las cosas que componen una determinada entidad, para poder encontrar todas las cosas, que pertenecen a ser un "maestro" en el sistema, por ejemplo, y ponerlas en un maestro de llamada de clase. Pero si varios "nombres" que se superponen, y relacionados con el comportamiento, tales como un "estudiante" con algunos datos y las operaciones de superposición con una "persona", pero con algunas diferencias marcadas, entonces se nos enseña que en lugar de replicar el código común, debemos elevar el carácter común en una clase base, y relacionar los tipos entre sí, a través de la herencia. En otras palabras, es común reunidos dentro de una clase, y la variabilidad, es capturada mediante la ampliación de esa clase, y la introducción de las variaciones. Encontrar las similitudes y variabilidades, dentro de un sistema, y de expresarlos, el núcleo central del diseño.
Elementos comunes, suelen ser las partes que son difíciles de identificar de forma explícita, ¿no porque?, no los reconocen, sino porque son tan fácilmente reconocibles intuitivamente y es difícil detectarlos. Por ejemplo, si digo, "vehículo", ¿qué imagen le viene a la cabeza? Si hacemos este ejercicio, con un grupo de personas, cada uno tendrá una imagen diferente, sin embargo, habrá concordancia amplia entre todos ellos. Sin embargo, si comenzamos a enumerar los diversos vehículos imaginado, los diferentes tipos de variabilidad comienzan a emerger y categorizar los mismos (esperamos), de manera que todavía puede tener un conjunto de elementos comunes entre los vehículos.
Variabilidad positiva y negativa
La variabilidad, puede venir en dos formas básicas, una de las cuales es fácilidad de reconocer, y la otra mucho más difícil. Variabilidad, es positiva cuando la variabilidad se produce en la forma de añadir a la base común. Por ejemplo, imagine la abstracción deseado que es el de un mensaje, como un mensaje SOAP o correo electrónico. Si decidimos que un tipo de mensaje, tiene una cabecera y el cuerpo, y dejar los diferentes tipos de mensajes a usar eso como el carácter común, y luego una variabilidad positiva, en este es un mensaje que tiene un valor particular en su cabecera, tal vez la fecha y hora que fue enviada. Este suele ser fácilmente capturados, en construcciones del lenguaje, en el paradigma orientado a objetos, por ejemplo, es relativamente trivial, para que crear un mensaje a la subclase, que añade el soporte para la fecha y hora de envío.
Variabilidad negativa, sin embargo, es mucho más complicado. Como puede deducirse, una variabilidad negativa elimina o contradice alguna faceta, de la comúnicación deun mensaje que tiene un encabezado, pero no del cuerpo (como un mensaje de confirmación utiliza, la infraestructura de mensajería), es una forma de variabilidad negativa. Y, como probablemente ya se puede adivinar, la captura de esto en una construcción del lenguaje es problemática: ni C # ni Visual Basic, tiene una instalación para eliminar un miembro declarado en una clase base. Lo mejor que podría hacer en este caso es nulo, el retorno o no del miembro del cuerpo, que claramente puede causar estragos en cualquier código, que espera un órgano para estar presentes, tales como las rutinas de verificación que ejecuta un CRC, en el Consejo para garantizar que se transmitió correctamente.
(Curiosamente, los tipos de esquema XML, ofrecen la variabilidad negativa en sus definiciones de la validación del esquema, algo que ningún lenguaje de programación convencional pero ofrece, que es una de las formas en que la definición de esquemas XML ,puede crear desajuste contra los lenguajes de programación. Si esto se convertirá en una característica, en la próxima algún lenguaje de programación, que aún no escritas, y si sería una buena cosa a tener, es una interesante discusión mejor tenía más de cerveza.)
En muchos sistemas, la negativa se suele manejar con código explícito construye en el cliente de nivel-es decir, le toca a los usuarios del tipo de mensaje que hacer algún tipo de if / else, se prueba para ver qué tipo de mensaje es, antes de examinar el Consejo, de que hace que el trabajo puesto en el mensaje de la familia casi irrelevante. El exceso de variabilidad negativa, escapar el diseño suele ser la causa subyacente de las llamadas de los desarrolladores para "terreno de juego a todos y empezar de nuevo."
Vinculante Comunalidad y la variabilidad
En el momento actual, que en común y la variabilidad, se establecen con variación con cada paradigma, y en general, cuanto más cerca en tiempo de ejecución, que puede obligar a esas decisiones, el control más que dar a los clientes, y usuarios sobre la evolución del sistema y en su conjunto. Cuando se habla de un paradigma particular, o la técnica dentro de un paradigma, es importante reconocer en cuál de estos cuatro "los tiempos se unen" la variabilidad de patadas en:
1. Fuente tiempo.
Este es el tiempo, antes de que el compilador genere incendios hacia arriba, cuando el desarrollador (o alguna otra entidad), genera la creación de los archivos de origen que eventualmente se integrarán en el compilador. La Generativa de técnicas de Código, como la plantilla T4 del motor, y en menor grado el sistema de ASP.NET funcionan en un origen de enlace en tiempo.
2. Tiempo de compilación.
Como su nombre lo indica, este enlace se produce cuando el compilador pasa sobre el código fuente, para hacer en bytecode compilado, o las intrucciones ejecutables del CPU. Una gran parte de la toma de decisiones se finaliza aquí, aunque no toda ella, como veremos.
3. / Carga.
Vincular el tiempo En el momento de cargar el programa y se ejecuta, un punto adicional de la variabilidad se activa, basada en los módulos específicos (asambleas, en el caso de; NET DLL, en el caso de código nativo de Windows), que se cargan. Esto se conoce comúnmente como, en o un complemento al estilo de arquitectura plug, cuando es aplicado en una escala del programa de nivel general.
4. Tiempo de ejecución
Durante la ejecución del programa, ciertas variabilidades pueden ser capturadas sobre la base de entrada del usuario, y toma de decisiones y ejecución de código potencialmente diferentes (o incluso generado), sobre la base de las decisiones y / o de entrada.
En algunos casos, el proceso de diseño, tendrá que empezar desde que los "tiempos se unen" y trabajar hacia atrás, para averiguar qué construcciones del lenguaje puede apoyar la exigencia, por ejemplo, un usuario puede querer tener la posibilidad de añadir / eliminar / modificar la variabilidad, en tiempo de ejecución (de modo que no tenemos que volver a través de un ciclo de compilar o código de recarga), lo que significa que cualquiera que sea el paradigma del diseñador utiliza, que debe ser compatible con una gran variabilidad en tiempo de ejecución obligatoria.
Desafío
En mi artículo anterior, que dejé a los lectores una pregunta:
Como ejercicio, piense en esto: NET Framework 2.0 introdujo los genéricos (tipos de parámetros). ¿Por qué? Desde una perspectiva de diseño, ¿para qué sirven? (Y para que conste, las respuestas de "Nos permite tener colecciones con seguridad de tipos", no viene al caso de Windows Comunicación Foundation, que utiliza ampliamente los genéricos, con claridad en formas que no son sólo acerca de las colecciones con seguridad de tipos.)
La visita parcial) de la aplicación (de una clase Point, en la figura 1, lo que representa un cartesianasde puntos X / Y, como coordenadas de píxeles, en una pantalla, o una gráfica más clásica.
Figura 1 Ejecución parcial de una clase Punto
1. Clase Pública punto
2. Pública Sub New (ByVal As Integer XX, YY ByVal As Integer)
3. Me.X = XX
4. Me.y = YY
5. End Sub
6.
7. Público de la Propiedad X () As Integer
8. Pública y Propiedad () As Integer
9.
10. La Función Pública a Distancia (ByVal otros puntos) As Double
11. Dim xdiff = Me.X - other.X
12. Dim YDiff = Me.y - other.y
13. System.Math.Sqrt Retorno ((xdiff xdiff *) + (YDiff YDiff *))
14. End Function
15.
16. Invalida la Función Pública es igual a (obj ByVal como objeto) As Boolean
17. "¿Son estos mismo tipo?
18. Si Me.GetType () obj.GetType = () Luego
19. otros atenuado como punto = obj
20. Volver other.X = Me.X Y other.y = Me.y
21. End If
22. Volver Falso
23. End Function
24.
25. Invalida la Función Pública ToString () As String
26. String.Format Retorno ("((0), (1)", Me.X, Me.y)
27. End Function
28.
29. End Class
En sí mismo, no es realmente tan emocionante. El resto de la aplicación, se deja a la imaginación del lector, porque no es central para la discusión.
Tenga en cuenta, que esta implementación Point, ha hecho algunas suposiciones sobre la forma en puntos se supone que es utilizado. Por ejemplo, X e Y, los elementos del Punto son números enteros, lo que significa que esta clase no puede representar el punto fraccional, tales como los puntos en (0.5,0.5). Inicialmente, esto puede ser una decisión aceptable, pero inevitablemente, una solicitud preguntándole a ser capaz de representar "fraccional Puntos" (por la razón que sea). Ahora, el desarrollador tiene un problema interesante: ¿Cómo representar esta nueva exigencia?
A partir de los conceptos básicos, vamos a hacer el "Oh Señor, no hagas eso", basta con crear una nueva clase Point, que utiliza puntos flotantes de los miembros, en lugar de miembros de pleno derecho, y ver lo que se desprende (véase la figura 2, tenga en cuenta que PointD, es corta para "punto doble," lo que significa que utiliza en dobles). Como es bastante claro, hay una gran cantidad de solapamiento conceptual, aquí entre los dos tipos de punto. De acuerdo con el carácter común / la teoría de la variabilidad de diseño, eso significa que necesita para capturar de alguna manera las partes comunes, y permitir la variabilidad. Objeto clásico de la orientación que nos han de hacerlo a través de la herencia, elevando el carácter común en una clase o interfaz base (punto), a continuación, la aplicación que en las subclases (PointI y PointD, tal vez).
Figura 2 Un nuevo punto con la clase de punto flotante miembros
1. Public Class PointD
2. Pública Sub New (ByVal como XX YY doble, ByVal As Double)
3. Me.X = XX
4. Me.y = YY
5. End Sub
6.
7. Público de la Propiedad X () As Double
8. Pública y Propiedad () As Double
9.
10. La Función Pública a Distancia (ByVal otros puntos) As Double
11. Dim xdiff = Me.X - other.X
12. Dim YDiff = Me.y - other.y
13. System.Math.Sqrt Retorno ((xdiff xdiff *) + (YDiff YDiff *))
14. End Function
15.
16. Invalida la Función Pública es igual a (obj ByVal como objeto) As Boolean
17. "¿Son estos mismo tipo?
18. Si Me.GetType () obj.GetType = () Luego
19. otros atenuado como PointD = obj
20. Volver other.X = Me.X Y other.y = Me.y
21. End If
22. Volver Falso
23. End Function
24.
25. Invalida la Función Pública ToString () As String
26. String.Format Retorno ("((0), (1)", Me.X, Me.y)
27. End Function
28.
29. End Class
Problemas interesantes surgen al intentar esto, sin embargo. Propiedades de primer lugar, X e Y, necesitamos un tipo asociado con ellos, pero la variabilidad son las dos preocupaciones diferentes en subclases, cómo coordenadas X e Y, sean almacenados y representados por lo tanto, a los usuarios. El diseñador siempre puede simplemente optar por el mayor ancho / /, representación más amplia, que en este caso sería una doble, pero esto significa tener un punto que sólo pueden tener valores enteros, se ha perdido como una opción, y se deshace de todos los el trabajo que la herencia era la intención de permiso. Además, debido a que están relacionados por herencia ahora, las dos implementaciones de punto que pueden heredar, son supuestamente intercambiables, por lo que debe ser capaz de pasar una PointD, en un método PointI Distancia, que puede o puede no ser deseable. Y es un PointD de (0.0, 0.0), equivalente (como en Iguala) a un PointI, de (0,0). Todas estas cuestiones tienen que ser considerados.
Incluso, si estos problemas son de alguna manera fijos o hechos problemas tratables, surgen otras. Más tarde, puede ser que desee un punto, que acepte los valores más grandes que se hace en un entero. ¿O sólo los valores absolutos positivos (es decir, el origen está en la esquina inferior izquierda), se considera aceptable. Cada uno de estos requisitos diferentes significará nuevas subclases de punto, que se deben crear.
Dando un paso atrás, por un momento, el deseo original era volver a utilizar el carácter común de la aplicación del punto, pero permiten la variabilidad, en el tipo o la representación de los valores que conforman el punto. En el ideal, según el tipo de gráfico, que estamos trabajando, debemos ser capaces de elegir la representación en el momento en el Punto se ha creado, y sería a sí mismo como un tipo totalmente distinto, y diferente, que es precisamente lo que los genéricos hacer.
Hacer esto, sin embargo, representa un problema: El compilador, insiste en que "Rep" de tipos necesariamente no tienen "+" y "-", operadores definidos por ella, porque piensa que quiere colocar, en cualquier tipo de posible aquí de los enteros, Longs, cadenas, botones, DatabaseConnections o cualquier otra cosa, que viene a la mente, y eso es claramente un poco variable. Así, una vez más, necesitamos expresar algo en común, con el tipo que se pueden utilizar aquí, en la forma de una restricción genérica sobre los tipos "Rep" puede ser (ver Figura 3).
Figura 3 Una restricción de tipo genérico
1. Pública GPoint clase (De Rep (Como IConvertible IComparable,))
2. Pública Sub New (ByVal XX como Rep, YY ByVal como Rep)
3. Me.X = XX
4. Me.Y = YY
5. End Sub
6.
7. Público de la Propiedad X () Como representante
8. Y la propiedad pública () Como representante
9.
10. La Función Pública a Distancia (ByVal otros GPoint (De Rep)) As Double
11. Dim xdiff = (Me.X.ToDouble (Nothing)) - (other.X.ToDouble (Nothing))
12. Dim YDiff = (Me.Y.ToDouble (Nothing)) - (other.Y.ToDouble (Nothing))
13. System.Math.Sqrt Retorno ((xdiff xdiff *) + (YDiff YDiff *))
14. End Function
15.
16. Invalida la Función Pública es igual a (obj ByVal como objeto) As Boolean
17. "¿Son estos mismo tipo?
18. Si Me.GetType () obj.GetType = () Luego
19. otros atenuado como GPoint (De Rep) = obj
20. Retorno (other.X.CompareTo (Me.X) = 0) y (other.y.CompareTo (Me.Y) = 0)
21. End If
22. Volver Falso
23. End Function
24.
25. Invalida la Función Pública ToString () As String
26. String.Format Retorno ("((0), (1)", Me.X, Me.Y)
27. End Function
28.
29. End Class
En este caso, se imponen dos restricciones: una para asegurarse de que cualquier "representante" de tipo, pueden ser convertidos a valores de tipo double (para calcular la distancia entre los dos puntos), y el otro para asegurarse de que el componente de valores X e Y, se pueden comparar para ver si están greater-than/equal-to/less-than, unos a otros.
Y ahora el motivo de los genéricos, se hace más claro: que apoyan en otro "eje" de la variabilidad en el diseño, uno que es radicalmente diferente de la del eje tradicional basada en la herencia. Se permite que el diseñador, para hacer la aplicación, en común, y los tipos que va a utilizar por la aplicación que se variabilidades.
Tenga en cuenta, que esta aplicación supone que la variabilidad, la que se produce en tiempo de compilación, en vez de en el enlace / tiempo de carga o tiempo de ejecución si el usuario quiere o necesita especificar el tipo de la X / Y, los miembros del punto en tiempo de ejecución, a continuación, un solución diferente es necesario.
Not Dead (o Hecho) ¡Sin embargo!
Si todos los de diseño de software, es un ejercicio de gigante en común y la variabilidad, a continuación, la necesidad de entender el diseño Multiparadigmático queda claro: Cada uno de los diferentes paradigmas, ofrece diferentes maneras de lograr esto en común, la variabilidad, y la mezcla de los paradigmas crea confusión y conduce a las convocatorias de una reescritura completa. Así como el cerebro humano, comienza a confundirse cuando tratamos de mapa tridimensional construye en nuestra cabeza en cuatro y cinco dimensiones, demasiadas dimensiones de la variabilidad en la confusión que el software causa.
En los artículos de la siguiente media docena, o algo así, voy a estar buscando en las diferentes formas en que cada paradigma con el apoyo de C # y Visual Basic, la estructural, orientadas a objetos, meta programación, los paradigmas funcional y dinámico que los directores proporcionan funcionalidad para la captura comunes y permite la variabilidad. Cuando estamos a través de todo eso, vamos a examinar cómo algunos de ellos, pueden ser combinados de maneras interesantes para hacer sus diseños más modular, extensible y fácil de mantener y todas esas otras cosas.
¡Feliz de codificación!
--------------------------------------------------------------------------------
Ted Neward, es un principal con Neward & Associates, una firma independiente especializada en la empresa. NET Framework y la plataforma de sistemas de Java. Ha escrito más de 100 artículos, es un MVP y # INETA altavoz C y ha sido autor y coautor de una docena de libros, incluyendo "F # 2.0 Profesional" (Wrox, 2010).También consulta y mentores con regularidad. Llegar a él en ted@tedneward.com con preguntas o peticiones de consulta, y leer su blog en blogs.tedneward.com.
Gracias a los siguientes expertos técnicos para la revisión de este artículo: Anthony Green
No hay comentarios:
Publicar un comentario