Академический Документы
Профессиональный Документы
Культура Документы
En este clásico juego que se ha utilizado desde años y con versiones para los primeros BASIC, se pregunta
para adivinar de qué animal se trata haciendo una serie de preguntas. Si el programa no adivina de qué
animal se trata, pregunta de manera que pueda aprender para juegos futuros,
En el comienzo , el juego solo conoce el perro, así que hasta que aprenda un poco más, será un poco
aburrido. También hará preguntas para distinguir cada nuevo animal de los anteriores cargados en su base
de datos.
El original de esto es uno de los innumerables tutoriales de distintos Smalltalk que hay en Internet.
Se acompaña el dibujo del original.
Podemos reconocer que es un árbol invertido con su raíz en la parte superior . Los nodos Question
(Pregunta) representan las ramas y las hojas son los nodos Animal,
Elegir una de los animales mostrados (Dog, Snake, Eagle , Horse) (Perro, Serpiente, Aguila, Caballo) como
intentos de acierto y siga el +arbol de decisión desde la raiz.
Parece entonces que podemos construir nuestra base de conocimientos con dos clases de objetos, Animales
y Preguntas.
También debemos guardar el objeto raíz ( una Pregunta) en alguna parte para poder comenzar el juego.
Herencia de Clases
Ahora , agregaremos la clase Animal a nuestra imagen. Repasemos un poco la herencia de clases.
Busquemos por ejemplo en el System Browser la clase Form que hemos usado. Con la clase seleccionada,
aquellos afortunados que tienen más de un botón, pulsen botón derecho o h o expand hierarchy y les
mostrará un Class Hierarchy Browser.
El Browser mostrará alguna de las clases que ya existen en la imagen. Esta jerarquía es importante dado que
gobierna como una clase en particular “hereda” la funcionalidad de sus clases padres. Eligiendo un lugar
apropiado en la cadena de herencia para definir nuevas clase nos ahorrará tiempo n no escribirá código que
ya esta hecho (reusabilidad).
Clases y Superclases
Recordamos algunas definiciones. Vemos que una clase puede tener varias clase hijas. Estas se conocen
como subclases. La clase padre se conoce como Superclase
Relaciones Es un y Contiene un
Volvemos a nuestra clase Animal. Donde en la jerarquía de clases la creamos?. Lo primero a considerar es
que clase de información contiene. Mirando el diagrama vemos que cada animal conoce su nombre, esto es
que clase de animal es. Esta información estará en forma de una cadena de testo String en Smalltalk:
Ejemplo ‘Perro’. `Gato’, ‘Caballo’. Así una posible ubicación sería en la clase String
Si buscamos la clase String nos encontraremos lo siguiente
Veremos métodos que realmente no nos son útiles, como los primeros de la lista . En realidad , si pensamos
un poco , veremos que Animal no “Es un” String , sino que “Contiene un” String. Esta es una decisión
fundamental que los diseñadores de software hacen cuando hacen "object oriented analysis" sobre un
problema de diseño. A menudo el problema es lo suficientemente complejo como para dibujar un diagrama
del modelo de objetos que ilustre las relaciones entre los varios objetos en el sistema. Esta relaciones se
describen como Es un y Contiene un.
Entonces , ya que Animal contiene un String, es mejor que sea una subclase de Object.
| aOrAn |
aOrAn := nombre first isVowel ifTrue: ['an '] ifFalse: ['a '].
aStream nextPutAll: aOrAn; nextPutAll: self nombre.
printOn: aStream
"Answer the name of the receiver as a developer would wish to see it."
super printOn: aStream.
aStream nextPut: $(.
self displayOn: aStream.
aStream nextPut: $)
.Los mensajes #printString and #printOn:están definidos en la clase Object, de la cual Animal hereda. Lo
que acabamos de hacer se denomina overriding y reemplaza el mensaje de la clase por el mensaje de la
instancia
Agreguiemos nuevamente miAnimal printString al Workspace y mostremos.
Self y Super
En el último mensaje agregamos el uso de estos dos importantes conceptos.
Si en un mensaje, deseamos enviar otro mensaje al objeto receptor, entonces usamos la palabra especial self
para representar el objeto. Miremos el mensaje #printOn y veamos como trabaja. Queremos utilizar
#displayOn para imprimir el nombre del animal como parte de la representación total,
Lo hacemos mandando el mensaje #displayOn a self.
Un concepto mas complicado es el de super. Lo utilizamos cuando deseamos mandar un mensaje al receptor
pero no en ninguna declaración local (esto es en la clase ). Cuando utilizamos super , el sistema comienza la
búsqueda del mensaje a ejecutar , no en la clase del receptor sino en la superclase. Es frecuente querer
heredar la funcionalidad pero agregar funcionamiento, esto es lo que se hizo con #printOn.
inicialize
“Inicializar la base de conocimiento del juego de los Animales .
Al comienzo solamente conocemos el perro “
KnowledgeBase:= self nombre:= ‘Perro‘
Completando el juego
Ahora solo nos faltan pocos mensajes que terminarán de colocar todas las piezas juntas. Veamos un poco de
la forma en que encontraremos el código escrito en la nomenclatura inglesa.
Animal>>thisMethod
Indicates that thisMethod belongs on the instance side of the Animal class
Animal class>>thisMethod
Indicates that thisMethod belongs on the class side of the Animal class
Question>>thisMethod
Indicates that thisMethod belongs on the instance side of the Question class
Question>>thisMethod
Indicates that thisMethod belongs on the instance side of the Question class
El símbolo >> se utiliza como forma de documentar que el mensaje (método) pertenece a una clase
particular.
Haciendo preguntas
Cuando el juego funciona, la computadora nos hará preguntas. A medida que el juego recorra el árbol de
conocimiento en un momento en particular, estará en un nodo Pregunta o si le parece que conoce que
animal es , en un nodo Animal. Si repasamos el diagrama, vemos que todo el tiempo nos preguntará.
“Tiene alas ?” Para un objeto Pregunta o
“Estás pensando en un Águila?” para un objeto Animal.
Lo importante ahora es ver que podemos escribir el código del juego de tal manera de independizarnos del
tipo de nodo. Podemos hacerlo enviando un mensaje #ask a cada nodo e implementando un método
adecuado #ask en cada clase Animal y Pregunta. Este comportamiento es típico de la programación
orientada a objetos y se denomina Polimorfismo.
Así que agreguemos nuestros métodos polimórficos #ask a Pregunta y Animal. Colocarlos en la categoría
operaciones.
ask
| repuesta pregunta miAnimal |
pregunta := 'El animal es que piensa ',self texto.
repuesta _ FillInTheBlank request: pregunta.
repuesta = 'SI' ifTrue: [miAnimal _ self si.
repuesta _ 'El animal era ', miAnimal nombre.
PopUpMenu inform: repuesta
]
ifFalse: [miAnimal _ self no.
miAnimal ask]
Ahora el método Animal>>ask . Cuando es llamado, la computadora piensa que tiene una repuesta pare el
animal, así que pregunta si la repuesta es correcta, y si es así, gana el juego. Si no, pregunta por un nuevo
Animal para crearlo con la repuesta correcta y para una nueva Pregunta que sea distinta de la original.
Veremos que hay algunos nuevos mensajes que se envían para los que no hemos codificado métodos, pero
los haremos posteriormente.
Animal>>ask
ask
| repuesta pregunta newAnimal newQuestion |
pregunta := 'El animal es que piensa es ', self nombre.
repuesta _ FillInTheBlank request: pregunta.
repuesta ='SI' ifTrue: [PopUpMenu inform: 'Acerte '].
repuesta ='NO' ifTrue: [newAnimal := Animal prompt ].
newQuestion := Pregunta preguntarParaDiferenciar: self from: newAnimal.
pregunta := 'Desea continuar jugando ? '.
repuesta _ FillInTheBlank request: pregunta.
repuesta ='SI' ifTrue: [Animal playGame ].
Preguntando por un nuevo Animal
Vemos en el último método una necesidad de crear un nuevo Animal preguntando por su
nombre.
Animal class>>prompt
prompt
"Prompt for a new animal to add to the game"
| newName |
[newName isNil or: [newName isEmpty]] whileTrue: [
newName _ FillInTheBlank request: 'En que animal estaba pensando ?'.].
^self nombre: newName
Como vemos, el método usa una clase llamada Prompter, la que se utiliza para pedir al usuario una cadena
de texto. Esta se chequea para validez y se utiliza para crear una instancia de Animal utilizando nuestro
método #nombre . dado que el método #prompt pregunta por una nueva instancia, tiene sentido colocarlo en
la categoría creación de instancias. Recordar que es un método de clase, así que utilizar el browser
seleccionado para clases.
Ingresando una nueva Pregunta
Y finalmente , necesitamos un método para un nuevo objeto Pregunta.
Ahora a jugar
Estamos lista para agregar un último método para nuestro juego de los animales. Necesitamos un método
sencillo para comenzar el juego.
Animal class>>playGame
playGame
PopUpMenu inform: 'Piense un animal y yo intentare adivinar'.
KnowledgeBase ask.