Paradigmas de Lenguajes de Programación 2do Cuatrimestre de 2006 Práctica No 6 - Programación Orientada a Objetos Para resolver esta práctica, recomendamos usar el entorno “VisualWorks”, de distribución gratuita, que puede bajarse del sitio web de la materia bajo la sección Links. Ejercicios introductorios Ejercicio 1 ¿Qué responde Smalltalk cuando se le pide evaluar las siguientes expresiones? i. ii. iii. iv. v. vi. vii. viii. ix. x. xi. xii. xiii. 1 1 class (1+1) (1+1) class ’hola, mundo’ ’hola, mundo’ class #(7 6 5) #(7 6 5) class #(7 6 5) at: 1 (#(7 ’perro’ 5.24 $a) (#(7 ’perro’ 5.24 $a) (#(7 ’perro’ 5.24 $a) (#(7 ’perro’ 5.24 $a) at:1) at:2) at:3) at:4) class class class class Ejercicio 2 ¿Qué responde Smalltalk cuando se le pide evaluar las siguientes expresiones? Al evaluar una expresión, tener en cuenta el ambiente producido por las evaluaciones previas. Las variables en mayúsculas representan variables globales. i. ii. iii. iv. v. vi. vii. viii. ix. x. xi. xii. xiii. x := 2 X := 2 X := X+1 Y := Y+1 Y Y := (2 3 4) Y := #(2 3 4) Y at :1 Y := Y at :2 |n| n := 4 n |n| n := n+1 |n m| n := 4. m := 1. ^(n+m+X+Y) Ejercicio 3 Idem que el ejercicio anterior, suponiendo que se ha salvado la imagen producida por él. Página 1 de 9 Paradigmas de Lenguajes de Programación 2do Cuatrimestre de 2006 i. ii. iii. iv. v. vi. vii. viii. ix. x. xi. xii. xiii. xiv. xv. xvi. xvii. xviii. xix. [X. Y] [X. Y] class [X. Y] value Duplicar := [:n | 2*n] Duplicar value Duplicar value:5 (’Objeto’ at:2) isVowel ifTrue: [2. 3] ifFalse: [3. 4] [X>0] whileTrue: [X := X - 1] X 5 timesRepeat: [X := X + Y] X A := Array new. A := #(1 2 3 4 5 6 7) A do: [:n | X := X + n]. ^X A select: [:i | i factorial < (i*i)] A reject: [:i | (i even) & (i>4)] A collect: [:i | X + Y + i] 2 to:5 do:[:i | A at:i put:2*i] A [X<10] whileTrue: [X:=X+1. X==5 ifTrue: [^X]] Diseño de Clases y Manejo de Colecciones Ejercicio 4 Implementar los siguientes métodos: i. to: do: usando el método whileTrue:. ii. do: para la clase Array usando whileFalse:. iii. reject: usando select: y not. Ejercicio 5 Considerar el método de instancia verificar:aPartirDe:, implementado en la clase SequenceableCollection (superclase de las clases String y Array entre otras). Tener en cuenta que sólo la clase String posee un método de instancia asUpperCase cuyo efecto es cambiar las minúsculas del objeto receptor por las mayúsculas correspondientes. El método at: se encuentra implementado en la clase Object, superclase de Collection, que es a su vez superclase de SequenceableCollection. verificar: patron aPartirDe: unIndice |posCadena posPatron cadenaChar patronChar| posCadena := unIndice. posPatron := 1. [ cadenaChar := self at: posCadena. patronChar := patron at: posPatron. cadenaChar = patronChar ] whileTrue: [ posCadena := posCadena + 1. posPatron := posPatron + 1. Página 2 de 9 Paradigmas de Lenguajes de Programación 2do Cuatrimestre de 2006 (posPatron > patron size) ifTrue: [^true]. (posCadena > self size) ifTrue: [^false]. ]. ^false. i. ¿Cuál es el efecto del mensaje verificar:aPartirDe: cuando es enviado con parámetros adecuados a un objeto adecuado? ii. ¿Cuál es el resultado de las siguientes evaluaciones? i. ’Or. Objetos’ verificar: ’Obj’ aPartirDe: 5 ii. ’Or. Objetos’ verificar: #($O $b $j) aPartirDe: 5 iii. ’Or. Objetos’ verificar: ’Obj’ aPartirDe: 4 iv. ’Or. Objetos’ verificar: ’O’ aPartirDe: 5 v. #($O $b $j $t) verificar: ’bj’ aPartirDe: 3 vi. #($O $b $j $t) verificar: #($b $j) aPartirDe: 2 iii. Si se modifica el método verificar:aPartirDe: cambiando la quinta lı́nea por: cadenaChar := self asUpperCase at: posCadena. ¿cuáles son los resultados de las evaluaciones del ı́tem anterior? Ejercicio 6 Agregar un método a la clase Number que represente la estructura de control “for”. El método debe poseer la siguiente interfaz: valor inicial to: condición step: incremento body: cuerpo Donde valor inicial es una instancia cualquiera de Number, condición es un bloque de código de un argumento que devuelve true o false, incremento es un bloque de código de un argumento que devuelve un valor, y cuerpo es un bloque de código de un argumento. La expresión debe devolver nil. Por ejemplo, la siguiente expresión imprime 1234 y evalúa a nil: 1 to: [:i | i < 5] step: [:i | i + 1] body: [:i | Transcript show: i printString] Ejercicio 7 Definir una clase Complex que implemente la clase de los números complejos. Definir los siguientes métodos: i. Re e Im, que devuelvan la parte real e imaginaria, respectivamente, del objeto receptor. ii. re:im:, tal que el mensaje re:a im:b inicialice el objeto receptor con parte real a y parte imaginaria b. iii. sum:, tal que el efecto de c sum:d sea actualizar c con c+d, donde + es la suma de números complejos. iv. abs, que devuelva el valor absoluto del objeto receptor. v. + (infijo), que devuelva la suma compleja de sus dos argumentos. vi. printOn: para mostrar complejos de modo adecuado. Sugerencia: ver cómo está implementado el método con el mismo nombre en la clase predefinida Fraction. Página 3 de 9 Paradigmas de Lenguajes de Programación 2do Cuatrimestre de 2006 Herencia Ejercicio 8 Sean las clases Uno, Dos y Tres, tales que Tres es subclase de Dos, y Dos es subclase de Uno. Las tres clases tienen métodos a y b definidos ası́: Class: Uno Methods: Class: Dos Methods: Class: Tres Methods: a ^2. a ^8. a ^super b. b ^self a. b ^super b. b ^super a. Sean uno, dos y tres instancias de las clases Uno, Dos y Tres respectivamente. ¿Cuáles son los resultados de las siguientes evaluaciones? i. ii. iii. iv. v. vi. uno a uno b dos a dos b tres a tres b Ejercicio 9 Se tienen definidas en Smalltalk las clases A, B y C. Todos los métodos presentados son de instancia, con excepción del método new de la clase C, que es un método de clase. Object subclass: #A print Transcript show: ’Soy la clase A’. hacerAlgo self print. A subclass: #B print Transcript show: ’Soy la clase B’. B subclass: #C print Transcript show: ’Soy la clase C’. hacerAlgo super print. new ^super new. ¿Qué mensajes se imprimen en el Transcript, si dentro de una ventana de Workspace se evalúan las siguientes expresiones? Página 4 de 9 Paradigmas de Lenguajes de Programación 2do Cuatrimestre de 2006 i. ii. b b c c := B new. hacerAlgo. := C new. hacerAlgo. Ejercicio 10 Se tienen las clases A, B, C, D donde A es superclase de B y C, y C es superclase de D, y no hay otra relación de herencia entre ellas cuatro. ¿Cómo debe hacerse para conseguir que valga lo siguiente? i. x esA debe devolver true para cada instancia x de A o de sus subclases, y false para cada x que no sea instancia de A ni de sus subclases. ii. x esBoC debe devolver true para cada instancia x de B o de C, o de las subclases de ambas, pero false para cada x que no sea instancia de B ni de C ni de subclases de ellas. iii. x esSoloC debe devolver true para cada instancia x de C y false para cada instancia de cualquier otra clase, inclusive subclases de C. Ejercicio 11 Se tienen 2 clases: A y B tal que B es subclase de A. Cada una tiene una variable de instancia, a y b respectivamente, con métodos de instancia para asignar y obtener los valores. La clase A tiene 2 métodos de instancia: imprimir self calcular. calcular ^((self geta) + 1). La clase B tiene 2 métodos de instancia: imprimir |b| b:=self calcular. super imprimir. calcular ^((self getb) * 2). Dado el siguiente código: |a b| a:= A new. b:= B new. a seta:2. b seta:3. b setb:4. a imprimir. b imprimir. Describa brevemente la ejecución. ¿Qué se devuelve? Describa el contenido de las variables de instancia de cada objeto, al finalizar la ejecución. Página 5 de 9 Paradigmas de Lenguajes de Programación 2do Cuatrimestre de 2006 Ejercicios de Parcial Ejercicio 12 Se cuenta con la clase Figura, que tiene los siguientes métodos: perimetro ^((self lados) sumarTodos). lados ^self subclassResponsibility. donde sumarTodos es un método de la clase Collection, que suma todos los elementos de la colección receptora. El método lados debe devolver un Bag (subclase de Collection) con las longitudes de los lados de la figura. Figura tiene dos subclases: Cuadrado y Circulo. Cuadrado tiene una variable de instancia lado, que representa la longitud del lado del cuadrado modelado; Circulo tiene una variable de instancia radio, que representa el radio del cı́rculo modelado. Se pide que las clases Cuadrado y Circulo tengan definidos su método perimetro. Implementar los métodos que sean necesarios para ello, respetando el modelo (incompleto) recién presentado. Observaciones: el perı́metro de un cı́rculo se obtiene calculando: 2 · π · radio, y el del cuadrado: 4 · lado. Consideramos que un cı́rculo no tiene lados. Aproximar π por 3,14. Ejercicio 13 i. En Smalltalk, agregar a la clase Collection un método con la siguiente interfaz: collectCircular: unosBloques donde unosBloques es una colección secuencial de bloques de código (es decir, instancias de la clase BlockClosure) con un parámetro de entrada cada uno. A diferencia del método collect:, este método aplica a cada elemento de la colección receptora del mensaje un bloque de código perteneciente a unosBloques. El orden de aplicación de los bloques debe ser circular, comenzando con el primero y aplicando uno por vez. La colección unosBloques no debe ser modificada por el método. Por ejemplo, la evaluación de la siguiente expresión: #(1 2 4 3) collectCircular: (Array with: ([:i | i * 2]) with: ([:i | i + 1]) with: ([:i | ’hola’])) da como resultado: #(2 3 ’hola’ 6) ii. Se cuenta con la clase Mazo, subclase de OrderedCollection, que contiene una secuencia de cartas. También está disponible la clase Jugador, que posee un método de instancia tomarCarta:, que recibe una carta y la agrega a la mano del jugador. Utilizando el método collectCircular:, definido en el item anterior, se pide definir el siguiente método en la clase Mazo: repartir: unosJugadores donde unosJugadores es una colección secuencial de objetos de tipo Jugador. El método repartir debe repartir las cartas del mazo entre los jugadores lo más equitativamente posible. Esto significa que si la cantidad de cartas es múltiplo de la cantidad de jugadores, todos los jugadores terminarán con la misma cantidad de cartas, y en caso contrario un Página 6 de 9 Paradigmas de Lenguajes de Programación 2do Cuatrimestre de 2006 subconjunto de los jugadores se quedará con una carta menos. Deben repartirse todas las cartas del mazo, y el mazo debe quedar vacı́o luego de invocar a repartir:. El método devuelve nil. Ayudas: La clase BlockClosure tiene definido el método value:, que evalúa el bloque receptor pasándole un parámetro. Ejemplo: [:n|n*2] value: 10 devuelve 20. Las colecciones secuenciales (subclases de SequenceableCollection) tiene definido el método at:, cuyo único parámetro es un ı́ndice y devuelve el elemento cuyo ı́ndice es el especificado. Ejemplo: #(7 8 10 9) at: 3 devuelve 10. Asumir que la clase Mazo posee el método removeAll que elimina todos las cartas del mazo receptor. Ejercicio 14 En Smalltalk, se ha definido la clase Mail de la siguiente manera: Object subclass:#Mail instanceVariableNames: ’encabezado cuerpo’ armarMensaje ^encabezado, procesar: cuerpo procesar: unCuerpo ^unCuerpo Además de la clase Mail, existen otras dos clases: MailFirmado y MailCifrado. MailFirmado tiene un método de instancia firmar: unMensaje con: unaFirma, que se encarga de firmar el mensaje completo (encabezado y cuerpo). MailCifrado tiene un método de instancia cifrar: unCuerpo con: unaClave, que se encarga de encriptar el cuerpo de un mensaje. Se pide completar MailFirmado y MailCifrado, agregando los métodos y variables de instancia que se consideren necesarios de formar tal que armarMensaje funcione de la forma esperada. Se debe evitar repetir código en la implementación propuesta. Indicar la relación de herencia entre las clases involucradas. Ejercicio 15 i. En Smalltalk, agregar a la clase Collection un método con la siguiente interfaz: inject: primerValor and: segundoValor into: operacion donde operacion es un bloque de código de tres argumentos que se evalúa una vez por cada elemento del receptor, con dicho elemento como tercer argumento. En la n-ésima evaluación, el primer y segundo argumento de operacion corresponden al resultado de la evaluación n-1 y n-2 respectivamente. La primera evaluación comienza evaluando operacion, con primerValor como primer argumento, segundoValor como segundo argumento, y el primer elemento del receptor como tercer argumento. La segunda evaluación toma el segundoValor como primer argumento y el resultado de la primera Página 7 de 9 Paradigmas de Lenguajes de Programación 2do Cuatrimestre de 2006 evaluación como segundo argumento. El método debe devolver la última evaluación de operacion. El orden de recorrido de los elementos es el dado por el do:. Por ejemplo, la evaluación de la siguiente expresión: #(’c’ ’d’ ’e’) inject: ’a’ and: ’b’ into: [:a :b :c | a, b, c] da como resultado: ’abcbabcde’ (el resultado es cada iteracion serı́a: 1)’abc’, 2)’babcd’ y 3)’abcbabcde’) ii. Utilizando inject:and:into:, definido en el item anterior, se pide redefinir el método usual de Collection: inject: valor into: operacion de forma tal que se comporte exactamente como la versión original de inject:into:. Ayudas: La clase BlockClosure tiene definido el método value:, que evalúa el bloque receptor pasándole un parámetro. También están disponibles en la misma clase los métodos value:value: y value:value:value: para bloques de dos y tres argumentos respectivamente. Ejemplo: [:n|n*2] value: 10 devuelve 20. Ejercicio 16 i. En Smalltalk, agregar a la clase Collection un método con la siguiente interfaz: selectAnd: unasCondiciones donde unasCondiciones es una colección de bloques de código (es decir, instancias de la clase BlockClosure) con un parámetro de entrada cada uno y que devuelven un valor booleano. A diferencia del método select: básico, este método requiere que todas las condiciones sean verdaderas para incluir un elemento de la colección receptora en la colección resultado. Por ejemplo, la evaluación de la siguiente expresión: #(1 5 2 4 7 3 6) selectAnd: (Array with: [:i devuelve #(5 7) | i odd] with: [:i | i >= 5] ) ii. Se cuenta con la clase Red, subclase de Set, que contiene un conjunto de máquinas (instancias de la clase Maquina). La clase Maquina tiene un método de instancia recursos que devuelve el conjunto de recursos disponibles en esa máquina (por ejemplo: impresoras, scanners, etc.). Utilizando el método selectAnd:, se pide agregar el siguiente método en la clase Red: findRecursos: unasCondiciones donde unasCondiciones es una colección de bloques con un parámetro de entrada y que devuelven un valor booleano. El método findRecursos: debe devolver todos los recursos, sin importar a qué máquina estuvieran asociados, que cumplan con todas las condiciones recibidas como parámetros. Ayudas: La clase BlockClosure tiene definido el método value:, que evalúa el bloque receptor pasándole un parámetro. Ejemplo: [:n|n*2] value: 10 devuelve 20. Página 8 de 9 Paradigmas de Lenguajes de Programación 2do Cuatrimestre de 2006 Las colecciones tienen un método addAll: que recibe una colección y agrega todos los elementos de dicha colección a la colección receptora Ejemplo: (Set with: 7 with: 8 with: 10) addAll: #(4 5); yourself devuelve a Set(4 5 7 8 10). Tener en cuenta que addAll: devuelve como resultado la colección que recibió como parámetro. Ejercicio 17 i. Agregar a la clase Collection un método con la siguiente interfaz: collectCond: unaCondicion ifTrue: bloque1 ifFalse: bloque2 donde unaCondicion, bloque1 y bloque2 son bloques con un parámetro de entrada cada uno. Este método tiene un comportamiento parecido a collect:, pero en lugar de aplicar el mismo bloque de código a cada elemento de la colección receptora del mensaje, aplica bloque1 a los elementos para los cuales vale unaCondicion, y bloque2 a aquellos para los que no vale. Por ejemplo, la evaluación de la siguiente expresión: #(1 2 4 3) collectCond: [:i | i even] ifTrue: [:i | i+1] ifFalse: [:i | i*3] da como resultado #(3 3 5 9), porque a los elementos pares les suma 1 y a los impares los triplica. ii. Utilizando collectCond:ifTrue:ifFalse:, agregar a la clase SequenceableCollection un método con la siguiente interfaz: collect: bloque1 alt: bloque2 donde bloque1 y bloque2 son bloques con un parámetro de entrada cada uno. Este método tiene un comportamiento parecido a collect:, pero aplica bloque1 a las posiciones con ı́ndice impar, y bloque2 a las posiciones con ı́ndice par. Por ejemplo, la evaluación de la siguiente expresión: #(1 2 4 3) collect: [:i | i+1] alt: [:i | i*3] devuelve #(2 6 5 9), porque a los elementos con ı́ndice impar les suma 1 y a los de ı́ndice par los triplica. Página 9 de 9