Está en la página 1de 27

Diseo orientado a objetos y software estadstico: patrones de diseo, UML y composicin vs.

herencia
Jordi Ocaa Rebull Alexandre Snchez Pla
Departament dEstadstica Universitat de Barcelona

RESUMEN
En este trabajo se analizan algunos aspectos del diseo de programas estadsticos. Aunque las ideas expuestas tienen una aplicabilidad ms general, los ejemplos se refieren, principalmente, a cuestiones relacionadas con la simulacin en Estadstica. El hilo conductor de la argumentacin es la idea de que bastantes de los patrones de diseo comnmente empleados en otras reas del desarrollo informtico, son especialmente aplicables en la creacin de programas estadsticos, a menudo reflejan de forma bastante directa conceptos estadsticos, y podran contribuir a mejorar caractersticas del software estadstico como la claridad y la facilidad de mantenimiento y de ampliacin. En concreto, se describen y se discuten con cierto detalle los patrones denominados Estrategia, Visitante (junto con el concepto de multimtodo) y Decorador, y se apunta la posible utilidad de otros patrones. La exposicin se basa en gran medida en la utilizacin de diagramas UML (Unified Modelling Language) como herramienta de modelado expresiva e independiente (hasta cierto punto) de lenguajes de programacin concretos.

1. INTRODUCCIN
En la actualidad, existe una estrecha vinculacin de la Estadstica con la Informtica. Esta vinculacin es evidente en el usuario de un mtodo estadstico, que precisa realizar anlisis sencillos o no tan sencillos y que para ello utiliza programas estadsticos especializados o herramientas de propsito ms general, como hojas de clculo. Pero tambin en el desarrollo de un nuevo mtodo estadstico surge, casi siempre, la necesidad de implementarlo de alguna manera en forma de herramienta informtica, o de realizar estudios de simulacin para determinar algunas propiedades del mismo. Es decir, en mayor o menor grado, una persona que investiga en Estadstica es tambin un desarrollador informtico. Chambers(2000) analiza estas cuestiones y deduce que, en realidad, existe una gradacin entre estos dos extremos de utilizacin de la Informtica en la Estadstica. Un usuario que inicialmente se limit a realizar tareas elementales (al menos desde su punto de vista, internamente estas tareas pueden ser de gran complejidad) con un programa estadstico puede verse en la necesidad de agruparlas de alguna manera para evitar la realizacin de tareas repetitivas, lo cual ya es un primer paso hacia la programacin. Ms an (y mucho ms difcil de automatizar que lo anterior), este usuario puede verse en la necesidad de extender de alguna manera la implementacin disponible de determinado mtodo estadstico. Por ejemplo, desea aplicar determinado mtodo de clasificacin jerrquica sobre una matriz de distancias calculada a partir de un ndice que no consta entre las opciones del programa que emplea. A partir de consideraciones de este tipo, Chambers(2000) propone una lista de cinco condiciones bsicas que debera cumplir toda herramienta informtica empleada en Estadstica: 1. Especificacin fcil de tareas sencillas;

2. capacidad de refinamiento gradual de las tareas; 3. posibilidades ilimitadas de extensin mediante programacin; 4. desarrollo de programas de alta calidad; y 5. posibilidad de integrar los resultados de los puntos 2 a 4 como nuevas herramientas informticas. Una de las consecuencias ms directas de las condiciones anteriores es que el estadstico debera contar con un entorno de trabajo y de desarrollo orientado a objetos. Aunque la adscripcin de una herramienta de este tipo a este paradigma informtico parece ciertamente muy conveniente, no proporciona una garanta segura de que el material desarrollado a partir de ella vaya a ser extensible o de calidad, por citar las dos palabras clave de los puntos anteriores ms directamente relacionadas con la orientacin a objetos. Frecuentemente, los programas desarrollados por los estadsticos, an utilizando lenguajes de programacin orientados a objetos como S o Java, caen dentro de una de dos categoras posibles, asociadas a sendas estrategias de desarrollo. Una posibilidad es ignorar completamente el paradigma de la orientacin a objetos, de manera que en el mejor de los casos en cuanto a la extensibilidad- el resultado es una librera de funciones como la que hace unas dcadas se habra desarrollado en FORTRAN, con la salvedad de que las funciones estn agrupadas en unos contenedores llamados clases, que ms bien molestan. La otra posibilidad es abusar de las caractersticas ms llamativas de la orientacin a objetos, en especial de la herencia: todos los conceptos estadsticos representados tienen que acabar encajando en grandes y complejas clases, derivadas por herencia de otras clases ms generales, en general tambin muy complejas. Los autores tienen que reconocer que algunos de sus intentos previos de realizacin de libreras de clases y de aplicaciones, diseadas con la intencin de facilitar el empleo de, y la investigacin en, simulacin estadstica y remuestreo, incurrieron ms bien en este ltimo defecto. Este trabajo pretende plasmar parte de lo aprendido en estos pasados errores. Pretende ser una discusin sobre aspectos generales de diseo, sin entrar en consideraciones sobre la conveniencia de uno u otro lenguaje concreto, ni en consideraciones sobre la eficiencia u otras virtudes de algoritmos concretos y de sus posibles implementaciones en determinado lenguaje. La idea bsica consistir en mostrar que muchos de los llamados patrones de diseo son directamente aplicables al diseo de programas estadsticos, y que conciernen a partes de los mismos que se refieren a conceptos propiamente estadsticos. Los patrones se expresarn en UML (vase ms adelante) para emplear una notacin general, bastante expresiva. Si en alguna ocasin hay que entrar en algo ms de detalle, se ilustrarn los conceptos en Java. Un tema de investigacin relacionado, no tratado en este trabajo, es la posibilidad de que existan patrones de diseo especficos de este mbito concreto de aplicacin, el desarrollo de programas estadsticos, y de identificarlos si existen.

2. ALGUNOS CONCEPTOS PREVIOS


Se supone que el lector parte con un cierto conocimiento de las ideas bsicas del enfoque orientado a objetos. En caso contrario se recomienda la lectura previa de alguna descripcin general del tema, como el captulo primero de Eckel(2002), cuya versin original en ingls se puede descargar en la direccin Internet http://www.mindview.net/Books/TIJ/. La exposicin resultar ms motivadora si se tiene cierta experiencia en la utilizacin de algn lenguaje, o herramienta similar, orientado a objetos. Aunque pretende ser general, se supone que el desarrollo de programas se va a realizar dentro de lo que sera la ortodoxia de la programacin

orientada a objetos, de manera que se supone la existencia, en su sentido habitual, de conceptos bsicos como el de clase, mtodo o funcin miembro, herencia, etc el enfoque de los lenguajes clsicos como C++, Java, Eiffel o Samalltalk. Es cierto que, por ejemplo, es perfectamente concebible una programacin orientada a objetos sin el concepto de clase, substituido por conceptos alternativos como el de prototipo (Hallman, 1997), que existen lenguajes que implementan este enfoque (Self, Kevo, ) y que incluso pueden resultar ms apropiados en mbitos como Internet o el modelado de patologas clnicas. Pero se trata de enfoques todava lejos de un nivel mnimo de estandarizacin. Adems, el enfoque (platnico desde un punto de vista filosfico?) basado en clases encaja bien la manera de describir el mundo de la Estadstica, basado en conceptos como el de distribucin o estadstico: una distribucin de Poisson es una (es decir, desciende de una) distribucin discreta, una distribucin de Poisson de parmetro 2 es perfectamente concebible como un objeto, una realizacin de, la clase Poisson, etc.

2.1.

El concepto de patrn de diseo

El trmino patrn de diseo no es extremadamente preciso pero s muy til. En la forma en la que se suele entender actualmente fue acuado en Gamma y col.(1994), importante referencia que se suele designar abreviadamente como GoF1. Por la manera en que se emplea este concepto en esta referencia bsica y en la mayora de usos posteriores, se refiere a una manera especialmente inteligente y perspicaz de resolver un tipo general de problema. A pesar de constar el trmino diseo no se suele considerar que se refiera nicamente a la fase de diseo de un programa, es una solucin completa que incluye anlisis, diseo e implementacin. Un patrn de diseo no se considera bien especificado hasta que se ha podido plasmar en forma de cdigo en algn lenguaje, pero claramente no es una convencin o receta idiomtica, ligada a un lenguaje concreto, como podra la relacionada con cmo recorrer de forma eficiente un vector en C empleando aritmtica de punteros, por poner un ejemplo. Sin embargo, en GoF se remarca que un patrn puede serlo, tener sentido identificarlo como tal o no, dependiendo del lenguaje utilizado. En el lenguaje de implementacin elegido en GoF, C++, un patrn como herencia no tiene sentido (ya est implcito en el propio lenguaje) mientras que sera una solucin general muy adecuada a numerosos problemas si el lenguaje de implementacin fuese C, por ejemplo. En un mbito de problemas y de conceptos ms cercano a la Estadstica, y que trataremos con mayor detalle ms adelante, un patrn de diseo muy comn como objeto funcin segn la terminologa de Eckel(2003) o comando segn la terminologa de GoF, tiene sentido en Java o en C++, pero no en Python, donde todo, y en concreto cualquier mtodo o funcin miembro, es un objeto. Tampoco hay que confundir patrn de diseo con un algoritmo adecuado para resolver un tipo concreto de problema que, lgicamente, se tendra que implementar de forma distinta segn el lenguaje. Un patrn de diseo debe ser una especificacin muy general, una especie de invariante que se cumple en problemas de mbitos diversos y que define una solucin general y muy estable.

Por gang of four: E. Gamma, R. Helm, R. Johnson y J. Vlissides, la banda de cuatro. GoF suele servir para referirse a los autores, y en itlica, GoF, al propio libro. Los componentes de la banda de cuatro que nos ocupa no cayeron en desgracia como los integrantes del grupo de dirigentes chinos que recibi el mismo nombre durante la Revolucin Cultural.

A modo de intento de ilustracin del concepto de patrn, vamos comentar uno de los patrones identificados y analizados en GoF y cuya comprensin es crucial para entender el resto de este trabajo. Posiblemente es el patrn de diseo ms utilizado y entendido sin problemas por los usuarios de las herramientas de programacin orientadas a objetos. Nos referimos al patrn denominado en ingls Template Method, que tal vez se podra traducir como Mtodo prototipo. Lo que en ingls se suele denominar application frameworks, es decir las libreras de clases y similares que han sido diseadas para ser utilizadas en la elaboracin de aplicaciones concretas mediante especializacin posterior de sus clases, suelen estar llenas de mtodos prototipo. Se trata de mtodos que expresan secuencias de operaciones habituales en determinado mbito. Por ejemplo, en Estadstica un fragmento de tal mtodo podra ser (empleando una sintaxis cercana a la de Java y en particular considerando el texto a la derecha de // como un comentario hasta el final de la lnea):
Data datos; // una variable datos StatResult resultado;// variable resultado de clculo estadstico // Data y StatResult son clases muy generales resultado = datos.summarize( ); resultado.print( ); resultado.plot( );

Cuando de verdad se utilice este mtodo, el objeto datos sobre el que se ejecutarn las instrucciones anteriores ser de una clase descendiente de Data, mucho ms especializada que ella, una clase que probablemente ni exista cuando se cre el mtodo patrn. La clase que realmente tendr resultado tambin ser una especializacin de StatResult; de hecho la clase de resultado probablemente la decidir el mtodo summarize asociado a la autntica clase del objeto datos. Qu pasar realmente cuando se impriman y se dibujen unos resultados estadsticos contenidos en el objeto resultado depender de la definicin concreta de los mtodos print y plot para la clase de resultado. De esta manera se puede programar de una manera muy genrica y al mismo tiempo con unas posibilidades casi ilimitadas de extensin.

2.2.

Nociones sobre UML

Tal como especifica en la documentacin oficial de UML (vase, por ejemplo OMG, 1999) que se puede consultar, actualizada, en www.rational.com, UML (Unified Modelling Language) se define como un lenguaje consistente para especificar, visualizar, construir y documentar los artefactos de los sistemas de software, as como para el modelado de negocios. Efectivamente, UML es una notacin, definida a mltiples niveles, adecuada para especificar modelos, especialmente si stos utilizan conceptos orientados a objetos. La parte ms llamativa y ms utilizada es la notacin grfica. UML naci en 1994 como una fusin de los mtodos y las notaciones de G. Booch y J. Rumbaugh, a los que posteriormente se uni I. Jacobson2. Fue propuesto como un estndar en 1997, ante el OMG (Object Management Group), asociacin dedicada a hacer propuestas de estndares para la industria. Al margen de este
2

De todas maneras, tiene que quedar claro que UML es nicamente una notacin, no una metodologa de modelado.

reconocimiento oficial, finalmente obtenido, se ha ido imponiendo como un estndar de facto. Prueba de ello es que se utiliza como notacin en toda clase de documentos y publicaciones, y no solamente en las relacionadas con el modelado de software o el modelado de negocios, como indica la documentacin oficial. Por ejemplo, Garrido(2001), un libro dedicado a la simulacin discreta, representa los modelos a simular utilizando la notacin grfica de UML. Otra prueba del xito de UML es la multitud de herramientas CASE disponibles para utilizar cmodamente esta notacin. La notacin grfica de UML consta de varios tipos de diagramas. El lector interesado puede consultar alguna obra introductoria, como Stevens y Pooley(2000). En este trabajo utilizaremos exclusivamente diagramas de clases, suficientes para expresar las relaciones entre clases implicadas en los patrones de diseo descritos. Los diagramas son bastante expresivos y se intentarn complementar con explicaciones sobre la marcha.

3. QU ALGORITMO UTILIZAMOS?
3.1. Planteamiento
Es evidente que la eleccin del algoritmo ms adecuado para resolver un problema es crucial en Estadstica computacional, y en muchas otras reas. A menudo debemos escoger entre ms de un algoritmo posible de solucin de un mismo problema. En ocasiones las diferencias entre los algoritmos posibles se hallan en aspectos puramente computacionales es decir, para (intentar) obtener la misma solucin desde un punto de vista matemtico podemos optar entre varios algoritmos, que difieren en su velocidad, en su estabilidad numrica, etc. Este es el caso de los, a menudo numerosos, mtodos de generacin de variables aleatorias disponibles para una misma distribucin. En otras ocasiones la solucin no es ni siquiera la misma en teora, si bien es una de las soluciones aceptables en una aplicacin concreta. Por ejemplo, es frecuente poder optar entre varios posibles mtodos de estimacin para estimar los parmetros de un modelo no lineal, por citar una situacin comn. En cualquier caso, lo ms comn es que no exista el mejor algoritmo. Dependiendo de qu se pretende hacer y de las limitaciones, posiblemente ser mejor utilizar un algoritmo u otro. Por ejemplo, un algoritmo de generacin aleatoria puede ser ms veloz para determinado rango de los parmetros de la distribucin considerada, pero comparativamente ineficiente para otros valores de los parmetros. Incluso es posible que un algoritmo basado en la tcnica de rechazo sea siempre el ms eficiente, pero que en ocasiones sea preferible realizar una simulacin empleando un algoritmo de inversin de la funcin de distribucin, para aprovechar las propiedades de monotonicidad de este mtodo volveremos a hablar de este tema en la seccin final. El estadstico que se plantea escribir una librera de funciones o de clases que sea til para los investigadores que precisen hacer simulaciones de Montecarlo, y por lo tanto generar variables aleatorias, se encuentra, inexorablemente a poco que medite cul es el diseo ms adecuado, con el dilema de qu mtodos de generacin programa, y en general de cmo organiza todo este material (distribuciones concretas, mtodos de generacin para estas distribuciones, etc). El camino ms directo para crear una tal librera es, por ejemplo, el seguido por el lenguaje S (o R) y por paquetes estadsticos como S-Plus, SPSS o Statgraphics. Se dispone de un repertorio fijo de posibles distribuciones, las que se haya considerado que son las ms bsicas y, de una manera u otra (llamada a una funcin, men,), se da la

opcin de generar valores segn la distribucin elegida, sin controlar el mtodo concreto de generacin empleado de hecho, en general sin documentar de ninguna manera el mtodo empleado. Ciertamente esto permite cumplir el objetivo de hacer fciles las cosas bsicas, pero no permite una utilizacin ms avanzada por parte de usuarios ms avanzados. Este enfoque resuelve el dilema citado en el prrafo anterior simplemente ignorndolo. Todava bajo un enfoque funcional, una solucin consistira en crear una funcin de generacin aleatoria para cada distribucin, con todos los algoritmos de generacin considerados codificados en la misma. El cdigo de dicha funcin sera seguramente complejo y largo, aunque se podra hacer ms modular e inteligible delegando determinadas tareas en otras funciones, que, por ejemplo, acabasen de implementar los detalles concretos de cada posible algoritmo alternativo pero en todo caso sera conveniente la existencia de esta funcin fachada para simplificar la organizacin del cdigo, desligando los detalles de cules seran los parmetros propios de cada distribucin concreta, control de errores en los valores de estos parmetros, etc de los detalles referentes a cmo se realiza la generacin. Tambin sera algo difcil de utilizar, debido a los numerosos y complicados parmetros de entrada que requerira. Esta dificultad sera, no obstante, relativamente fcil de soslayar con un buen sistema de ayuda y tal vez con una buena eleccin de opciones por defecto si fuese posible en el lenguaje empleado. Una dificultad mucho ms seria se presentara cuando el algoritmo de generacin adecuado en un caso concreto no estuviese inicialmente previsto en el cdigo inicial. En este caso, el problema podra resultar sencillamente insoluble para un usuario que desease aprovechar parte de lo codificado previamente (solamente hacer algunos retoques o adiciones) y que no dispusiese del cdigo fuente de la funcin. La nica solucin posible ser codificar desde cero, reinventar la rueda. Disponiendo del cdigo fuente, seguramente sera posible entrar en los detalles internos de la funcin y hacer los cambios deseados, tarea difcil incluso para el propio autor de la funcin que, repetimos, posiblemente sera bastante larga y complicada. En principio, un enfoque ms conveniente lo proporcionara una librera de clases que, de alguna manera, representara los conceptos estadsticos implicados. Parece que una buena opcin (como mnimo es la ms comnmente empleada en las libreras existentes en este mbito) es organizar las distribuciones de probabilidad en una jerarqua de clases. La organizacin concreta de esta jerarqua es una cuestin bastante delicada. Supongamos que todas estas clases fuesen descendientes de una clase ancestora comn ProbabilityDistribution, a su vez con descendientes como UnivariateDistribution, con descendientes como UnivariateDiscrete o UnivariateAbsolutelyContinuous, de las cuales descenderan clases ms concretas como Poisson o Normal. Las clases ms generales seran, normalmente, abstractas. No se instanciaran nunca (es decir, nunca se crearan objetos de aquella clase) pero permitiran definir partes comunes de la interfaz, y posiblemente de la implementacin, de sus clases descendientes. Aparte de otros mtodos o funciones miembro dedicados a otras tareas propias de lo que se considerase la interfaz propia de estas clases (por ejemplo, cdf para calcular la funcin de distribucin o quantile para determinar cuantiles), todas ellas contaran con una funcin miembro asociada llamada, por ejemplo, nextRand, encargada de la tarea de generar valores aleatorios segn aquella distribucin. Ahora la organizacin del cdigo sera mucho ms lgica y modular. Para un objeto de (una instancia de) la clase Normal estara claro el significado de una llamada a su mtodo densidad, que tendra un efecto evidentemente distinto a la llamada del mismo mtodo para un objeto de clase Binomial lo cual ayudara a solucionar el problema de

nombres para designar todas estas funciones en un lenguaje funcional: binomialCdf, binomialPdf, NormalCdf, NormalPdf,

Figura 1. Eleccin del mtodo de generacin basada, exclusivamente, en la herencia

En un primer impulso (muy normal en quien se inicia en la programacin orientada a objetos), la implementacin de los posibles algoritmos de generacin para una misma distribucin se podra llevar a cabo especializando por herencia otras clases. Por ejemplo, para implementar el algoritmo de generacin de Ahrens y Dieter(1988), aplicable a la distribucin normal, una posibilidad sera crear una nueva clase, NormalAhrensDieter1988, especializando una clase general Normal, sobrescribiendo su mtodo nextRand pero lgicamente aprovechando (heredando) las otras partes de la misma. Normal podra implementar un mtodo sencillo (por ejemplo, el conciso aunque no especialmente eficiente algoritmo de Box y Muller, 1958) o simplemente ser abstracta y no proporcionar ninguna implementacin para nextRand. Aunque el enfoque anterior funciona, es un claro sobre abuso de la herencia, concepto por otra parte ciertamente til. Producira una jerarqua de clases muy intrincada, con rboles de gran profundidad, difcil de entender y de mantener. La Figura 1 trata de reflejar este hecho, empleando la notacin UML. Las clases se representan mediante rectngulos divididos en tres zonas (que no siempre se muestran), la primera de ellas indica el nombre de la clase, la central puede informar de posibles atributos (variables) contenidos en los objetos de la clase, la parte inferior se dedica a mostrar los mtodos

asociados a la clase. La relacin de especializacin (herencia) se muestra con una flecha en la que la lnea es continua y la punta est vaca. La flecha siempre seala de la clase ms especializada (la descendiente) a la ms general (la superclase). Pinsese adems en la todava mayor cantidad de clases que se generaran si, adems del posible algoritmo de generacin, se considerasen criterios adicionales de especializacin del concepto de distribucin. Un enfoque alternativo consistira en dotar ya de entrada a cada clase con mtodos distintos para los distintos algoritmos de generacin. Por ejemplo, se creara la clase Normal ya con los mtodos boxMullerNextRand, ahrensDieter1988NextRand, etc. Posiblemente tambin existira un mtodo general nextRand que internamente llamara a alguno de los otros, de acuerdo con el valor de algn parmetro de entrada que especificase el algoritmo a emplear. Son numerosas las objeciones que se pueden poner al enfoque anterior. Si los mtodos que implementasen cada algoritmo (boxMullerNextRand, ahrensDieter1988NextRand, ) fuesen pblicos, es decir, fuese posible acceder a ellos desde el exterior de la clase, produciramos clases con unas interfaces realmente complicadas, largas y distintas de una clase (distribucin) a otra. Un principio de diseo elemental es el de crear interfaces cuanto ms cortas y claras mejor. Alternativamente, estos mtodos podran ser privados, no ser accesibles desde el exterior de la clase. En este caso no seran tampoco modificables, aprovechables por herencia: no sera posible crear una simple variante de alguno de ellos. Ciertamente una posibilidad adecuada sera hacerlos protegidos, solamente accesibles por la propia clase y sus descendientes. Pero, en cualquier caso, est claro que este enfoque no es ms que un remedo del enfoque basado en crear

Figura 2. Estructura general del patrn de diseo Estrategia

mltiples funciones o una funcin muy general y compleja. En realidad todo lo planteado para los posibles algoritmos de generacin de cada distribucin (y planteable para otras muchas situaciones en Estadstica: algoritmos o mtodos de estimacin de los parmetros de una distribucin o de alguna clase de modelos, algoritmos de optimizacin diversos, ) es muy comn en muchas otras

reas. Un patrn de diseo adecuado para esta clase general de problemas es el denominado Estrategia (Strategy en GoF) y esquematizado en la Figura 2. En este diagrama se introducen tres nuevos aspectos de la notacin: por una lado las interfaces, conjuntos de mtodos que especifican a qu mensajes ser capaz de responder una clase. Se indican igual que una clase con un estereotipo, una etiqueta con un significado especial en UML, que seala que se trata de una interfaz. Este concepto se discute un poco ms abajo. Por otro lado, la relacin que une determinada clase con una interfaz a la que implementa se indica con una flecha similar a la que representa la herencia, pero con la lnea discontinua. Finalmente, la relacin de composicin entre un objeto compuesto (en este caso, una distribucin) y una de sus partes (en este caso, un algoritmo de generacin) que se representa con una lnea terminada con un rombo, situado siempre en el lado del objeto compuesto3.

3.2.

Eleccin de algoritmo en tiempo de ejecucin: patrn Estrategia

En este patrn, los posibles algoritmos alternativos se implementan en una jerarqua de clases independiente de la jerarqua de clases de posibles clientes de estos algoritmos. Todos los algoritmos deben responder a una misma interfaz, deben de ser capaces de responder a determinado mensaje, implementado en un mtodo adecuado, por ejemplo execute ejecuta el algoritmo. Las clases que van a ser clientes de estos algoritmos, deben tener en su definicin un atributo que sea una referencia al objeto algoritmo concreto que en un momento dado est activo, vigente para aquel cliente. El mtodo de la clase cliente que realiza la operacin concreta que depende del algoritmo, operation en la Figura 2, en general se limitar a activar el mtodo execute del objeto algoritmo que en aquel momento tiene asignado como activo.

Dado que, tal como se comentar ms adelante, la duracin del objeto que representa el algoritmo de generacin debera estar limitada por la duracin del objeto distribucin, la relacin es una verdadera composicin, que se representa mediante un rombo en negro, relleno, y no una agregacin que se representa mediante un rombo vaco, en blanco.

Figura 3. El patrn Estrategia en la generacin de variables aleatorias

En la Figura 3 se ilustra el patrn Estrategia adaptado a la situacin planteada anteriormente, la eleccin dinmica del algoritmo de generacin. Otro ejemplo muy interesante, en el que los autores redescubren (o se adelantan a GoF) el patrn Estrategia, se halla en Hitz y Hudec (1994) para la estimacin del elipsoide de volumen mnimo en la determinacin la localizacin y la forma multivariante. En la Figura 3 se ponen de manifiesto algunos aspectos adicionales, presentes en general en la realizacin concreta de este patrn: Gracias a la herencia, basta con que una superclase general de la jerarqua de clases cliente (UnivariateDistribution en el ejemplo) tenga definida la referencia, genMethod, a los objetos que implementan algoritmos de generacin, y tenga definido el mtodo, nextRand, que activa el algoritmo. Ntese que esta referencia es genrica, se define como de tipo GenerationMethod, lo cual no impide que los objetos-algoritmo concretos a los que hace referencia sean en la prctica de clases ms especializadas (AhrensDieter1988, BucketsInversion,). La validez del sistema queda asegurada por el hecho de que todas estas clases concretas implementan la interfaz especificada por GenerationMethod, son capaces de responder al mensaje adecuado, en este caso nextRandom. Los detalles finales dependen del lenguaje de programacin concreto. En C++ GenerationMethod ser una verdadera clase, seguramente abstracta, y los algoritmos concretos debern estar representados por clases que, obligatoriamente, desciendan de ella. Hay ms flexibilidad en Java o en Object Pascal-Delphi, en los que existe el concepto diferenciado de tipo interfaz (interface), de manera que las clases que corresponden a algoritmos no deben pertenecer, forzosamente, a una misma jerarqua de herencia, basta con que implementen la interfaz GenerationMethod, es decir, que sean capaces de reaccionar a los mensajes definidos en ella. En realidad es un principio bsico del diseo orientado a objetos que, siempre que sea posible, es preferible programar pensando en interfaces y no en clases, mucho ms ligadas a una

implementacin concreta. Con algunos cambios, se podra especificar un diseo todava ms general y flexible en el que UnivariateDistribution, FiniteUnivariate, Normal, Binomial, etc seran interfaces. Al igual que las distribuciones deben tener una referencia al algoritmo de generacin empleado, es conveniente que los algoritmos de generacin tengan una referencia a la distribucin concreta (al objeto) que estn generando, por ejemplo para poder consultar los valores de sus parmetros. A diferencia de la referencia distribucin algoritmo que es genrica (genMethod es de tipo GenerationMethod), la referencia algoritmo distribucin es conveniente que sea ms especfica, lo cual puede ayudar a controlar posibles errores de empleo de algoritmos de generacin inadecuados para determinada distribucin. Por ejemplo, as se especifica que el algoritmo AhrensDieter1988 solamente es vlido para la clase Normal (o descendientes) mientras que BucketsInversion es vlido para cualquier objeto de una clase descendiente de FiniteUnivariate. La principal ventaja de este patrn de diseo es la mayor modularidad que proporciona. Las clases correspondientes a las distribuciones (o a otros conceptos estadsticos) y las clases correspondientes a los algoritmos concretos de generacin (o de estimacin, de bsqueda en un rbol) se pueden mantener y crecer de forma independiente. Su principal inconveniente (como de la mayora de patrones) es que aade un nivel de direccionamiento adicional, que puede implicar una cierta carga de computacin adicional. Dependiendo de la naturaleza de lo realizado por los algoritmos, este precio puede ser, en trminos relativos, despreciable. Por ejemplo, as ser normalmente si el algoritmo de generacin no genera un solo valor, sino muchos, cada vez que se activa.

3.3.

Patrones de diseo relacionados con Estrategia

Es comn que al mismo problema o situacin sea aplicable ms de un patrn de diseo, ya sea por que son posibles soluciones alternativas, ya sea por que intervienen en partes distintas de la solucin. Como mnimo dos patrones adicionales, cuya descripcin no detallaremos, pueden intervenir en la situacin concreta que estamos analizando, la generacin de variables aleatorias. Se trata de los patrones Factora y Objeto nulo. Ntese que es indispensable que los objetos distribucin y los objetos algoritmo de generacin estn siempre sincronizados, en el sentido de que si, por ejemplo, a un objeto que representa una distribucin se le modifican los valores de los parmetros, este cambio tambin tiene que afectar al objeto que representa el algoritmo de generacin asociado que posiblemente almacena internamente valores que ser preciso actualizar en funcin de los parmetros de la distribucin. Existen diferentes maneras de manejar esta necesidad de coherencia entre objetos. Una solucin completa la proporciona el patrn Observador (Observer) aunque parece demasiado complicado para la situacin tratada. Dado que en la relacin entre un objeto distribucin y el algoritmo de generacin asociado solamente intervienen dos objetos, parece bastar con que estos objetos estn fuertemente vinculados, en concreto que solamente se pueda acceder al algoritmo de generacin (incluyendo el hecho de crear el correspondiente objeto algoritmo) desde el objeto distribucin. La duracin de los objetos algoritmo tambin tiene que estar limitada por la duracin de los objetos distribucin, no pueden existir algoritmos libres no asociados a una distribucin. Para ello basta con que las referencias citadas en prrafos anteriores (campo genMethod) sean privadas y que los algoritmos de generacin no tengan constructores accesibles, pblicos. Ello nos conduce a la necesidad de utilizar alguna de las variantes del patrn de diseo

denominado comnmente Factora (Factory), que en cierta manera independiza la creacin de objetos en un cierto punto de un programa, del empleo de sus constructores, que obligan a hacer una referencia explcita a la clase concreta. De las variantes de este patrn, la ms adecuada parece la denominada Factora polimrfica (Polymorphic Factory) descrita en Eckel(2003). Mediante la implementacin de este patrn es posible crear objetos de determinada clase simplemente llamando un mtodo de una clase general (la factora, en nuestro ejemplo bajo control de las clases distribucin) y especificando una cadena de caracteres con el nombre de la clase deseada para el objeto, como informacin de entrada a dicho mtodo. Este enfoque de creacin de algoritmos de generacin est implementado en la librera de clases Montecarlo, escrita en Java por el primer autor y a cuya versin preliminar se puede acceder en <<falta: referencia a pagina web>>. La necesidad de sincronizacin entre objeto distribucin y objeto algoritmo de generacin puede representar cierta carga computacional extra (si reinicializar el algoritmo de generacin implica clculos complejos), que convendra evitar si va a ser frecuente que se modifiquen los parmetros de un mismo objeto distribucin sin que durante el mismo intervalo de tiempo se vaya a producir ninguna generacin aleatoria. Una posibilidad es hacer que (siempre al crearlo, y tambin cuando as se indique explcitamente) el objeto distribucin no haga referencia a ningn algoritmo de generacin. Pero este enfoque puede provocar algunos problemas de coherencia, y en particular que, en muchos lugares, los mtodos de la distribucin tengan que incluir sentencias condicionales (if) para verificar si, en un momento dado, aquella distribucin tiene asociado o no un algoritmo de generacin, lo cual perjudica la simplicidad y legibilidad del cdigo, como mnimo. Una solucin sencilla la proporciona el patrn de diseo Objeto nulo (Null object), vase por ejemplo Henney(1999), que se basa en la definicin de una clase que responda a la interfaz de los algoritmos pero dotada de mtodos nulos, que no realicen ninguna accin. La librera Montecarlo, citada antes, incluye una variante de este patrn en la que el generador nulo s que realiza una tarea importante: ante un mensaje en el que se solicite generacin aleatoria, el generador nulo construye un generador de verdad que queda asociado a la distribucin y que captura la peticin de generacin.

4. DEBO INCLUIRLO TODO EN LA INTERFAZ?


4.1. Introduccin
Un error de diseo muy habitual al crear una librera de clases es pretender que stas incluyan mtodos e informacin para manejar todos los conceptos de la correspondiente rea de aplicacin. Por ejemplo, al crear una librera de clases de distribuciones de probabilidad, una estrategia comnmente seguida es incluir, ya de entrada en las superclases iniciales, gran cantidad de mtodos o funciones miembro, todo aquello que el autor prevea que va a ser solicitado de dichas clases: clculo de la funcin de densidad, de la funcin de distribucin, media, varianza, momentos (funcin general o hasta que orden?), moda, cuantiles, Procediendo de esta forma se pretende conseguir que todos los objetos creados a partir de las clases descendientes, ms concretas, respondan a una misma interfaz, muy general y amplia. Este diseo contradice el principio de que es deseable la mxima modularidad. Las interfaces deberan ser cuanto ms concisas mejor: toda clase debera tener unas atribuciones muy concretas, asociadas a una interfaz lo ms concisa posible. En cualquier caso, implementar en la prctica una tal librera puede representar una cantidad de trabajo enorme y no exento de

curiosidades como tener que desactivar mtodos que no tengan sentido para determinadas clases concretas. Evidentemente existen varias posibilidades aceptables, pero qu hay que hacer con el mtodo que calcula la media, la varianza, etc de una distribucin de Cauchy? Un enfoque alternativo al anterior es partir de unas superclases muy escuetas e ir ampliando su interfaz mediante el uso de la herencia. El resultado final son interfaces de las clases concretas muy amplias pero que no corresponden a una interfaz comn, lo cual no facilita la programacin genrica recurdese lo indicado para el patrn de diseo mtodo prototipo. Ahora no es posible referirse en determinados lugares a un objeto de una clase muy general (como ProbabilityDistribution o UnivariateDistribution) contando con que aquel cdigo funcionar para objetos de clases mucho ms especficas, Poisson, Gamma, etc, clases que incluso pueden no existir en el momento de la programacin del cdigo genrico. En cualquier caso, ninguno de los dos enfoques anteriores permite una extensin fcil, especialmente si no disponemos de (o no queremos modificar) el cdigo fuente de la librera de clases ya creada. La Figura 4 trata de reflejar la multiplicacin de clases que provocara la necesidad de incluir un mtodo como interQuartilicRange que, inexplicablemente (tal vez por agotamiento) haba sido omitido en la jerarqua de clases original. La jerarqua tiene omisiones evidentes para hacerla sencilla, pero al mismo tiempo pretende ilustrar que de nada servira aadir el mtodo en una superclase como UnivariateDistribution, si esto tuviese sentido. Las clases concretas Binomial, Poisson,

Figura 4. Multiplicacin de clases al extender por herencia

etc no descenderan de ella y por lo tanto no heredaran el mtodo. Una va de solucin ms elegante se basa en crear, independientemente de la jerarqua de clases inicial que se desea ampliar, nuevas clases que representen las nuevas funciones que se desean incorporar, es decir, alguna variante de objeto funcin o comando, citado anteriormente. As se podra crear una clase denominada InterquartilicRange con una funcin miembro eval, que devolviese valores reales (por

ejemplo double de Java) y que esperase recibir un argumento de entrada de una clase general como UnivariateDistribution. En Java se especificara algo como:
public class InterquartilicRange { public double eval (UnivariateDistribution distri) { // clculos para determinar el recorrido intercuartlico } }

Se supone que eval(UnivariateDistribution distri) sera suficientemente general como para evaluar el recorrido intercuartlico para todas las distribuciones univariantes. Pero an en este caso, parece lgico pensar que para algunas distribuciones concretas el mismo clculo podra ser mucho ms eficiente, de manera que parecera muy razonable ampliar (ya de entrada o en un descendiente) la interfaz de la clase InterquartilicRange aadiendo mtodos para manejar el caso de distribuciones ms especficas4. Adems, si de una manera genrica se desea poder cambiar la funcin estadstica, entendida aqu como funcin de un objeto que represente una distribucin, seguramente la clase InterquartilicRange tendra que descender de una clase ms general, llammosla por ejemplo StatFunction, con, como mnimo, el mtodo general, de firma public double eval (UnivariateDistribution distri) definido en su interfaz:
public class InterquartilicRange extends StatFunction{ public double eval (UnivariateDistribution distri) { // clculos para determinar el recorrido intercuartlico // en general } public double eval (Normal distri) { // clculos para determinar el recorrido intercuartlico // para la distribucin normal } }

Concretando ms, consideremos el siguiente fragmento de cdigo genrico:


StatFunction operator; UnivariateDistribution distr; double valor = operator.eval(distr);

Sintcticamente, lo anterior es correcto. Pero es posible que no haga lo que se podra pensar en principio. Si la autntica clase de operator es InterquartilicRange y la de distr es Normal, incluso alguien con experiencia en la programacin en Java, podra pensar que la tercera lnea del ejemplo ejecutara el mtodo, ms eficiente y adecuado en este caso, de firma public double eval (Normal distri). La realidad es que, en este caso, siempre se ejecutar el mtodo ms general. Esto se debe a que, en tiempo de ejecucin, se decide la clase concreta para la que se ejecutarn los mtodos (siempre que se trate de un mtodo virtual, en Java todos los mtodos son virtuales). Por lo tanto, correctamente, se buscarn los mtodos disponibles en la clase InterquartilicRange. Pero la sobrecarga de mtodos, en la mayora de lenguajes (C++, Java,) es aplicable al momento de la compilacin, no a la ejecucin del programa. Cuando est analizando las tres lneas de cdigo anteriores, el compilador desconoce la clase concreta del objeto que recibir como valor de entrada el mtodo eval, mtodo asociado a un objeto del cual, lo nico
En este caso este proceder no complica demasiado la interfaz (como mnimo en lenguajes que permiten sobrecarga de mtodos), ya que todos los mtodos se llaman igual, eval. Simplemente se proporcionan opciones ms especficas y eficientes, cuando las hay.
4

que se puede asegurar, es que ser de clase StatFunction o de alguna de sus descendientes (totalmente desconocida en ese momento). Como la interfaz de StatFunction incluye el mtodo public double eval (UnivariateDistribution distri), el cdigo resulta correcto sintcticamente y queda establecido que, en su momento, se ejecutar un mtodo con aquella firma, definido en la clase que corresponda, pero no un mtodo de firma public double eval (Normal distri), posibilidad ni siquiera considerada en el momento de la compilacin.

4.2.

Mtodos mltiples y el patrn de diseo Visitante

En la discusin previa se ilustra un concepto importante, tanto en general como en computacin estadstica. Se trata del concepto de mtodo mltiple o multimtodo, vase, por ejemplo, Saar(2000). La mayora de lenguajes orientados a objetos (incluyendo los ms comunes, como Smalltalk, Java y C++) implementan un mecanismo de resolucin simple. Los mtodos son despachados o resueltos (el sistema decide ejecutar una u otra versin de los mismos) en funcin de la clase del objeto que activa el mtodo la clase real, no necesariamente la declarada en una parte de cdigo donde interviene, que puede ser una superclase de la primera. Un multimtodo, en cambio, tiene un mecanismo de resolucin mltiple (por traducir de una manera que no suene muy mal el trmino comnmente empleado en ingls multiple dispatch): se decide qu mtodo ejecutar en funcin no solamente de la clase del objeto que activa el mtodo sino tambin de la clase real de los restantes argumentos o de parte de ellos. Este til concepto ha sido elegantemente incorporado en el lenguaje S, a partir de su versin 4 (que no hay que confundir con el nmero de versin de un programa basado en S, como S-plus), vase Chambers(1998). En un lenguaje como Java, utilizando el mecanismo de reflexin (por el cual, los objetos pueden conocer cosas de si mismos o de otros objetos, como su autntica clase), o por otras vas, es posible simular el concepto de mtodo mltiple (Boyland y Castagna, 1997). Si solamente es necesario implementar mtodos de resolucin doble (entendidos como mtodos que se ejecutan en funcin del objeto que los activa y de uno solo de sus parmetros) y si la necesidad de extensin mediante un mecanismo de este tipo ya estaba prevista en la jerarqua de clases original, una solucin limitada pero clara y fcil de implementar en lenguajes que no dispongan de multimtodos la proporciona el patrn de diseo Visitante (Visitor). La Figura 5 trata de esquematizar este patrn de diseo. En Visitante, la necesidad de resolucin doble se implementa mediante una doble llamada a mtodos de resolucin simple, la nica disponible. Todas las clases de la jerarqua cuyo repertorio de mtodos o funciones se quiere ampliar (en este caso las clases de la jerarqua que parte de VisitableClass) deben implementar un mtodo, denominado accept en la Figura 5, que haga que los correspondientes objetos acepten ser visitados por objetos de clases que implementen la interfaz Visitor. Estas ltimas clases (las Visitor) son las que realmente implementan las nuevas funciones (cada clase un tipo especfico de funcin), en el ejemplo mediante los mtodos actionOver. Dado que la llamada a la correspondiente funcin actionOver se realiza dentro de un mtodo de la clase visitada, lugar en el que est perfectamente clara cul es la clase del propio objeto que activa el mtodo (la referencia this en Java) se activar la versin de actionOver ms apropiada, la que escoger el mecanismo de sobrecarga de mtodos ya en tiempo de compilacin.

Como consecuencia de la aplicacin del patrn Visitante, con la incorporacin de un nico mtodo, accept, en todas las clases de una determinada jerarqua, la interfaz de todas estas clases se puede ampliar con un nmero ilimitado de nuevas funciones, funciones encapsuladas en clases que implementen una interfaz dada, Visitor en las

Figura 5. Estructura general del patrn de diseo Visitante

definiciones anteriores. El punto ms dbil de este patrn es el hecho de que la interfaz Visitor debe incluir mtodos para todas las clases de la jerarqua de VisitableClass que tengan que ser visitables directamente, es decir, para las cuales se vaya a definir un mtodo actionOver especfico. Si se ampla la jerarqua de VisitableClass y se desea crear mtodos actionOver cuya firma incluya las nuevas clases, ser necesario ampliar y recompilar la interfaz Visitor y las clases que la implementan. Dentro de lo que cabe, esto no es tan grave ya que la jerarqua de VisitableClass ser normalmente ms estable que la de Visitor. Esta ltima estar bajo el control del usuario, que la utilizar como va de ampliacin de la primera. La Figura 6 ilustra el patrn Visitante para ampliar las funciones ejecutables sobre una jerarqua de distribuciones que slo incluye cuatro distribuciones concretas, Binomial, Poisson, Normal y Exponential, y tres superclases ms generales, UnivariateDiscrete, UnivariateAbsolutelyContinuous y UnivariateDistribution. Esquemticamente, las correspondencias entre la definicin general del patrn y este ejemplo son: Caso general (Figura 5) Jerarqua VisitableClass y descendientes Mtodo accept VisitableClass Interfaz Visitor en la jerarqua Ejemplo (Figura 6) Jerarqua UnivariateDistribution descendientes y

de Mtodo evaluate en la jerarqua de UnivariateDistribution Interfaz StatFunction

Clases FirstVisitor, SecondVisitor que Clase InterquartilicRange que implementa

implementan la interfaz Visitor Mtodo actionOver

la interfaz StatFunction Mtodo eval

La jerarqua con raz en la clase UnivariateDistribution se ampla con una nueva funcin estadstica (un posible visitante), representada por la clase InterquartilicRange, que implementa la interfaz StatFunction. El mtodo evaluate, presente en todas las clases de la jerarqua de distribuciones, siempre tiene la misma forma, en Java sera:
public double evaluate (StatFunction func) { return func.eval (this); }

Si la autntica clase del objeto unaDistr es Binomial y la de unaFunc es InterquartilicRange, la ltima lnea de
UnivariateDistribution unaDistr; StatFunction unaFunc; double val = unaDistri.evaluate(unaFunc);

se traducir, en ltima instancia, en una llamada del mtodo eval(Binomial ) de

Figura 6. El patrn Visitante en una jerarqua de distribuciones de probabilidad

InterquartilicRange, que se supone que es lo que se pretenda. Las tres superclases UnivariateDiscrete, UnivariateAbsolutelyContinuous y UnivariateDistribution intervienen en el patrn (constan en la interfaz StatFunction y en las clases que la implementan) ya que, posiblemente, para ellas se crearn versiones generales del mtodo eval, que sern aplicables a sus clases descendientes que no hayan sido explcitamente incluidas en el patrn. Por ejemplo, supngase que descendiendo de

UnivariateDiscrete, se crea una nueva clase NegativeBinomial a la que no se incluye en el patrn, es decir, no se aade un mtodo eval especfico para esta clase en la interfaz StatFunction y en la clase InterquartilicRange y similares. Si unaDistr es en realidad un objeto de clase NegativeBinomial y unaFunc sigue siendo un objeto de clase InterquartilicRange, en la ltima lnea del cdigo anterior el clculo correspondiente ser finalmente realizado por el mtodo eval(UnivariateDiscrete ) de la clase InterquartilicRange, tal como ocurrira tambin en el caso de la extensin por herencia. No es necesario el patrn Visitante, asociado a las limitaciones comentadas anteriormente, si realmente se utiliza una verdadera implementacin de los multimtodos. En un lenguaje como Java, como ya se ha comentado anteriormente, es posible simular este mecanismo, en general utilizando el mecanismo de la reflexin, y por lo tanto pagando un precio considerable en eficiencia.

5. PATRONES DE DISEO EN SIMULACIN ESTADSTICA


En esta seccin final se discute con algo ms de detenimiento el diseo de programas que implementen mtodos de Montecarlo en Estadstica. Este ejemplo, algo ms complejo que los anteriores, es un escenario en el que son aplicables algunos de los patrones introducidos en las secciones precedentes, adems de motivar el empleo de algunos patrones adicionales.

5.1. Un proceso de simulacin se puede representar como un objeto compuesto


La Figura 7 refleja la estructura habitual de los procesos de simulacin de Montecarlo en Estadstica. En ellos hay una serie de elementos (objetos?) y subprocesos que casi siempre estn presentes: Un modelo probabilstico, completamente especificado p.e. distribucin y valores de los parmetros, tipo de

un proceso de muestreo sobre el modelo anterior p.e. generacin de muestras con observaciones independientes e idnticamente distribuidos, iid, de un tamao prefijado, a partir de la distribucin anterior, un estadstico que se evala sobre cada una de las muestras generadas y que produce un resultado de cierto tipo p.e. cierta prueba de significacin (test) que produce un resultado final de tipo 0 (se acepta la hiptesis nula) o 1 (se rechaza la hiptesis nula, y otro estadstico que se evala sobre la muestra finalmente obtenida de valores del estadstico anterior p.e. la frecuencia relativa de 1, para estimar la potencia o el nivel de significacin real del test anterior.

Ntese que esta es tambin la estructura de la fase de simulacin del mtodo bootstrap, con la salvedad de que el modelo probabilstico completamente especificado (en caso contrario no sera posible generar nada a partir de l) es la distribucin emprica asociada a una muestra real o ms generalmente, un modelo probabilstico estimado a partir de la muestra real.

Modelo probabilstico,

completamente especificado (gran) muestra x1 = ( x11 ,, x1n ) t ( x1 ) = t1 de m valores del x2 = ( x21 ,, x2 n ) t ( x2 ) = t2 estadstico

xm = ( xm1 ,, xmn )

t ( x m ) = tm

Generacin de nsim=m muestras independientes (o no) segn F p.e. formadas por n rplicas N ( , 2 ) iid Estadsticos resumen

1 m (t j t ) 2 varF ( t ) m 1 j =1 G G ( ; F ) , etc.

Leyes de los grandes


nmeros
Figura 7. Esquema general de una simulacin de Montecarlo en Estadstica

La mayora de simulaciones de Montecarlo en Estadstica se ajustan a una estructura (patrn?) como la descrita anteriormente. La gran diversidad de posibilidades procede de las muchas combinaciones posibles en las clases de los objetos (distribucin, estadstico, proceso de muestreo) que intervienen. Lgicamente, sera posible representar toda esta diversidad utilizando (abusando de) el mecanismo de la herencia, lo cual dara lugar a una jerarqua muy intrincada de clases. La discusin anterior sugiere que a este tipo de situaciones es aplicable uno de los patrones de diseo ms utilizados y generalmente bien comprendidos, denominado habitualmente objeto compuesto. Un objeto que define una simulacin es un compuesto de objetos de diversas clases. En gran medida, cada familia concreta de

Figura 8. Interfaz RandomSampler

experimentos de simulacin viene definida por las clases de los objetos que constituyen este objeto compuesto, es decir, por la distribucin concreta utilizada para generar las muestras, por el estadstico concreto calculado sobre cada muestra, etc. Una estructura de datos, un compuesto, que resulta muy flexible como elemento constructivo en este mbito est reflejada en las figuras 8 y 9, todas ellas tomadas directamente del diseo de la librera de clases Montecarlo, citada anteriormente. La Figura 8 es la definicin de la interfaz RandomSampler. Toda clase que implemente esta interfaz, en esencia, debe ser un objeto compuesto del que dependa una funcin stat (un objeto-funcin de clase Statistic) y debe ser capaz de generar muestras (mtodo sample) de tamao prefijado o del tamao (n) que se indique. El valor devuelto por sample siempre tiene la estructura (stat(x1), , stat(xn)), resultado de evaluar stat sobre cada uno de los elementos de la muestra generada. Si stat es nulo se supone que es la identidad, el resultado de sample es directamente (x1, , xn). La Figura 9 muestra dos clases importantes que implementan RandomSampler: IIDDistributionSampler y StatSimulator. Aunque no es un detalle importante, ambas especializan una clase, SamplerImplementation, que contiene algunas definiciones comunes y en concreto una referencia al estadstico, stat, que manejan.

La clase IIDDistributionSampler, tal como sugiere la firma de sus constructores, es capaz de producir muestras aleatorias simples a partir de la distribucin de probabilidad que se especifique, con la funcin stat (que puede ser la identidad) evaluada sobre cada elemento de la muestra.

Figura 9. Clases que implementan RandomSampler

La misin de la clase StatSimulator es muestrear otro muestreador, utiliza las muestras generadas por otra clase que implemente RandomSampler para construir el resultado final de la evaluacin de su mtodo sample. La posibilidad de que un objeto compuesto pueda formar parte a su vez de otro compuesto, con total transparencia (en el sentido de que los objetos resultantes siempre obedecen a la misma interfaz) proporciona una gran flexibilidad, adecuada para representar un gran nmero de situaciones. Como muestra de la potencia de este concepto, considrese la siguiente situacin:
Statistic t = new OneSampleTTest (m0); Statistic fr = new RelativeFrequency(); ProbabilityDistribution distr = new Normal(m, s); int n = 10; int nsim = 10000; RandomSampler simulator = new StatSimulator( new IIDDistributionSampler( distr, n), t, nsim); double p = fr.eval( simulator.sample());

Omitiendo bastantes detalles accesorios, supngase que la primera lnea del ejemplo anterior crea un objeto funcin t de clase Statistic que evala el test t de Student para una sola muestra, para contrastar la hiptesis nula de que la media poblacional es el valor contenido en m0 frente a la alternativa de que no es este valor. Un mtodo de t, seguramente denominado eval por coherencia con los nombres usados hasta ahora, devuelve finalmente el valor 0 en caso de aceptar la hiptesis nula y el valor 1 en caso contrario. La segunda lnea construye un estadstico, fr, que evala la frecuencia relativa de 1 a partir de un vector de valores 0 1. La tercera lnea construye un objeto que corresponde a una distribucin normal con media y desviacin estndar especificadas en

m y s. La cuarta y quinta lneas definen el tamao muestral de las muestras sobre las que se evala t y el tamao muestral del estudio de simulacin, respectivamente. Las dos ltimas instrucciones pueden estar en un mtodo separado de las primeras, que habr recibido aquellos objetos como argumentos. La penltima instruccin construye un simulador, un objeto adecuado para generar un vector de 10000 valores 0 1, cada uno de ellos obtenido a partir de una muestra de tamao 10 sobre la que se ha evaluado el test t. La ltima instruccin realiza realmente la simulacin (instruccin simulator.sample( )) y evala la potencia estimada del test. En efecto: El objeto creado en la instruccin
new IIDDistributionSampler( distr, n)

ser capaz de producir muestras iid de tamao n a partir de la distribucin distr, que en este caso concreto es una normal. Puesto que no se ha especificado ninguna funcin al construirlo, su mtodo sample producir directamente valores de la forma x = (x1, , xn), vectores de tamao n generados a partir de una distribucin normal. Puesto que el objeto anterior ha sido pasado como primer argumento para la construccin del simulador,
new StatSimulator( new IIDDistributionSampler( distr, n), t, nsim);

este ltimo (el simulador) generar valores en su propio mtodo sample a partir del resultado de sample del objeto que ha recibido, sobre los que habr evaluado el estadstico t. Por lo tanto, el resultado de
simulator.sample()

tendr la forma (t(x1), , t(xnsim)). Supngase ahora que se desea realizar un estudio de simulacin sobre la robustez del test anterior, por lo que est previsto generar las muestras segn diversas distribuciones, alternativas a la normal. Toda la estructura anterior sera vlida, con la nica diferencia de que el objeto distr tendra que ser de otra clase, por ejemplo
ProbabilityDistribution distr = new Exponential( rate);

para que las muestras generadas correspondiesen, en realidad, a una distribucin exponencial.

5.2.

Ampliar las atribuciones de una clase: el patrn Decorador

La estructura descrita en la subseccin anterior es un ejemplo, en verdad algo complejo, de algo que se podra adaptar a un patrn de diseo cuyo objetivo principal es aumentar las atribuciones de una clase. Se trata del patrn denominado comnmente Decorador (Decorator) y en ocasiones Envoltura (Wrapper). En la seccin 4 tambin se plantearon vas para aumentar la interfaz, y por lo tanto las atribuciones, de una clase. El tipo de incremento que planteamos en esta seccin es ms general, puede referirse tanto a la ampliacin de su interfaz (perfectamente posible con Decorador) como a un incremento (o simplemente modificacin) de sus capacidades internas de proceso, sin alterar la interfaz. La Figura 10 muestra la estructura general del patrn Decorador. Supngase que en determinada aplicacin son importantes clases que implementan determinada interfaz, que hemos denominado Decorable. DecorableClass1 y DecorableClass2 son ejemplos concretos de clases que implementan esta interfaz. La clase Decorator contiene un atributo interno, decoratedObject, que es una referencia a un objeto de cualquier clase que implemente Decorable (por ejemplo una referencia a

Figura 10. Estructura general del patrn de diseo Decorador

un objeto de clase DecorableClass2 sera perfectamente admisible como valor de este atributo) e implementaciones de los mtodos de la interfaz Decorable que se limitan a activar los mismos mtodos del objeto especificado por decoratedObject. Por lo tanto, un objeto de clase Decorator, de existir, se comportara exactamente igual que el objeto referido en decoratedObject. Las clases FirstDecorator y SecondDecorator descienden de Decorator. La primera de ellas redefine el mtodo method2, aadindole cierta capacidad de proceso adicional. La segunda redefine method1 y aade un nuevo mtodo a su interfaz, additionalMethod. Ntese que, al construir objetos de estas clases, el constructor debe recibir una referencia a un objeto decorado, que pasar a ser el valor del atributo decoratedObject. Un objeto creado como
Decorable d = new FirstDecorator( new DecorableClass2( ));

se comportara exactamente igual que un objeto de clase DecorableClass2, excepto en su mtodo method2, que realizara cierto procesamiento adicional, previo al realizado por method2 en la clase DecorableClass2. De la misma manera, un objeto creado como
Decorable d = new SecondDecorator( new DecorableClass1( ));

respondera a la misma interfaz que un objeto de clase DecorableClass1 excepto en su mtodo method1, adems de disponer de un mtodo adicional en su interfaz en este caso una vez realizado el molde de tipo (typecasting) adecuado, ya que Decorable no incluye el mtodo additionalMethod:
(SecondDecorator)d.additionalMethod( );

Ntese la potencia de este mecanismo, que permite creaciones de objetos como:


new SecondDecorator( new FirstDecorator( new DecorableClass2( )));

para dotar de nuevas caractersticas o ampliar la interfaz, de forma transparente y sin necesidad de recurrir a la creacin de complicadas jerarquas que aadan todas estas funcionalidades mediante el mecanismo de la herencia5.

Figura 11. Implementacin de clculos en servidores remotos y tcnicas de reduccin de la varianza como decoradores

La Figura 11 ilustra la posible utilidad del patrn Decorador en simulacin estadstica. Suponiendo que se ha creado una jerarqua de clases del estilo de la descrita en la subseccin anterior, es posible concebir numerosas variantes sobre la misma, que podran ser fcilmente implementadas mediante este patrn. Una posibilidad la sugiere la necesidad de realizar simulaciones muy intensivas computacionalmente, que impliquen una gran carga de clculo. Es posible que, en este caso, se desee delegar gran parte de la computacin necesaria en un ordenador remoto, se supone que muy potente. El decorador Remote hara los preparativos necesarios para que sucesivas llamadas a los mtodos del objeto decorado fuesen redirigidas a un objeto remoto, posiblemente una copia exacta de ste (del objeto decorado), mediante algn mecanismo de invocacin remota, como RMI en Java o la especificacin CORBA, ms general. Otra posibilidad la sugieren algunos mtodos de reduccin de la varianza de aplicacin casi automtica, como el mtodo de las variables antitticas. Recurdese que si en una
Curiosamente, el sistema de entrada/salida de Java hace un uso intensivo del patrn Decorador, precisamente para prevenir una explosin de clases dedicadas a la gestin de la entrada/salida!
5

simulacin se desea estimar un parmetro interpretable como la esperanza de un estadstico t, E(t), a partir de una muestra de valores simulados del estadstico, (t1, t2, , tnsim), un esquema de muestreo que produzca observaciones iid del estadstico no es necesariamente la mejor opcin. En el caso iid la varianza de la media muestral de las observaciones simuladas es, como es bien sabido, var ( t ) = var ( t ) . nsim

En cambio, si las observaciones obtenidas por simulacin estn correlacionadas (pero siempre respetando la distribucin marginal del estadstico), la varianza ser: var ( t ) = var ( t ) + cov ( ti , t j ) nsim i, j

donde el sumatorio se extiende a aquellos pares de observaciones ij que tengan correlacin no nula. Si este sumatorio es negativo, la varianza de la estimacin ser menor que la correspondiente al caso de observaciones incorrelacionadas. Una posibilidad fcil de implementar es hacer que las observaciones estn organizadas en pares consecutivos independientes pero con correlacin negativa dentro de cada par:

( ( t , t ) ; ( t , t ) ; ; ( t
1 2 3 4

nsim 1

, tnsim ) )

( t2i 1 , t2i ) < 0, i = 1, , nsim 2


suponiendo, lgicamente, que nsim es par. Dada una funcin de distribucin univariante G, la distribucin bivariante con marginales G con la correlacin negativa ms extrema posible (la cota de Frechet H) es la asociada al vector aleatorio (G1(U), G1(1U)), donde U es una variable aleatoria con distribucin uniforme sobre (0,1). Normalmente no se generar directamente t2i-1 = G1(U2i-1), t2i = G1(U2i) ya que la obtencin de los valores del estadstico requerir la generacin previa de una muestra de tamao n de cierta variable aleatoria, t = t(x1, , xn). Pero si el estadstico es una funcin (aproximadamente) montona de las observaciones de la muestra y los elementos de la muestra se pueden generar por inversin y manteniendo la sincronizacin entre las secuencias de valores uniformes:

muestra 2i 1: x1 = F 1 (U1 ) , x2 = F 1 (U 2 ) ,, xn = F 1 (U n ) muestra 2i : x1 = F 1 (1 U1 ) , x2 = F 1 (1 U 2 ) ,, xn = F 1 (1 U n ) es de esperar que los pares de valores del estadstico estn negativamente correlacionados. En resumen, una implementacin sencilla de la tcnica de las variables antitticas (que no siempre funcionara, dependera de la forma concreta del estadstico y del algoritmo utilizado para generar las variables aleatorias), la proporcionara una clase decoradora, Antithetic en el ejemplo, que, antes de generar la muestra mediante el objeto RandomSampler correspondiente, alternase entre dos posibles secuencias de nmeros aleatorios, una complementaria de la otra. Esto se podra conseguir utilizando y alternando entre dos objetos de una clase asimilable a Random de Java tales que produjesen secuencias de nmeros pseudoaleatorios complementarias. La simulacin sobre la potencia de un test, descrita anteriormente, utilizara variables antitticas si el simulador se construyese de la manera siguiente:
RandomSampler simulator = new StatSimulator(

new Antithetic( new IIDDistributionSampler( distr, n)),t, nsim);

6. CONSIDERACIONES FINALES
Todo lo expuesto en las secciones anteriores pretenda demostrar que la utilizacin de un enfoque orientado a objetos en computacin estadstica (y en general) es una mejora significativa sobre otros enfoques, pero no necesariamente una garanta de calidad de los programas producidos. La discusin de los inconvenientes de algunos diseos ante determinados problemas (conseguir flexibilidad en la eleccin del algoritmo para solucionar determinado problema o realizar determinado proceso, ampliar las operaciones posibles sobre una jerarqua de clases estadsticas dada y disear programas de simulacin estadstica) ilustra las limitaciones del enfoque orientado a objetos. Por otra parte, sin proporcionar en general soluciones mgicas, determinados patrones de diseo proporcionan soluciones aprovechables en el mbito de la computacin estadstica. Los patrones considerados en este trabajo, y muchos otros que podran ser tiles en el desarrollo de programas estadsticos, proporcionan soluciones elegantes a determinados problemas y hacen que, en general, el software desarrollado sea ms fcil de mantener y de extender. Como contrapartida, normalmente implican algn nivel adicional de direccionamiento, que en casos concretos puede implicar una cierta prdida de eficiencia. Se usen o no patrones, nuestra conclusin final es que el tiempo dedicado a realizar un cierto anlisis y diseo previo, tratando de formalizar (en cierta forma) los conceptos a plasmar en forma de programas mediante una notacin como UML, no es un tiempo perdido, siempre que no se caiga en una anlisis-parlisis, el extremo contrario.

REFERENCIAS
Ahrens, J.H., Dieter, U. Efficient table-free sampling methods for the exponential, Cauchy and normal distributions. Computing, Commun. ACM, 31, 1330-1337, 1988. Box, G.E.P., Muller, M.E. A note on the generation of random normal deviates. Ann. Math. Statist. 29, 610-611, 1958. Boyland, J., Castagna, G. Parasitic methods: An implementation of multi-methods for Java. OOPSLA 97, Proceedings, Atlanta. SIGPLAN Notices, 32, 66-76, 1997. Chambers, J.M. Programming with Data. A Guide to the S Language. Springer, 1998. Chambers, J.M. Users, programmers, and statistical software. Journal of Computational and Graphical Statistics, 9, 403-422, 2000. Eckel, B. Thinking in Java. Prentice Hall, 2002. Eckel, B. Thinking in Patterns with Java. Libro en preparacin, la versin preliminar es accesible por Internet: http://www.mindview.net/Books/TIPatterns/. Gamma, E., Helm, R., Johnson, R., Vlissides, J. Dessign Patterns: Elements of Reusable Object-Oriented Software. Addisson-Wesley, 1994. Garrido, J.M. Object-Oriented Discrete-Event Simulation with Java. A Practical Introduction. Kluwer, 2001. Hallman, B. Are classes necessary? The Journal of Object-Oriented Programming, 10, 16-21, 1997.

Henney, K. Something for nothing. Java Report, 4, 74-80, 1999. Hitz, M., Hudec, M. Applying the Object Oriented paradigm to statistical computing. Proceedings in Computational Statistics, COMPSTAT 94, 389-394, 1994. OMG. Unified Modeling Language Specification. Version 1.3, June 1999 Saar, R. Extensions of software components using multimethods. The Journal of Object-Oriented Programming, 13, 12-16, 2000. Stevens, P., Pooley, R. Using UML: Software Engineering with Objects and Components. Addison-Wesley, 2000.

También podría gustarte