Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware...

147
Cafetera eléctrica OO

Transcript of Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware...

Page 1: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Cafetera eléctrica OO

Page 2: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Mark IV Special Coffee Maker

• En el libro “Designing object-oriented C++ applications using the Booch method” (1995) de Robert Martin, se plantea diseñar software orientado a objetos (OO) para implementarlo en C++ y,

• ejecutado en un pequeño sistema embebido que controle las distintas funciones de una cafetera eléctrica “especial”

Page 3: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Mark IV Special Coffee Maker

• la idea era demostrar que C++ era viable en este tipo de plataforma y que,

• el DOO (Diseño orientado a objetos) es una metodología apropiada para este tipo de sistemas

Page 4: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de
Page 5: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Mark IV Special Coffee Maker

• En el 2002, Robert Martin, en el libro “UML for Java programmers” retoma este ejemplo, puesto que, encontró que sus alumnos a menudo repetían algunos errores de diseño y,

• deseaba mostrarles porqué eran errores de diseño y cómo podían corregirlos

Page 6: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Especificación de Mark IV

Page 7: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Especificación de Mark IV

• La cafetera prepara hasta 12 tazas de café por vez.

• El usuario pone un filtro en el portafiltros, llena el filtro con café molido y coloca el portafiltros en su receptáculo.

• El usuario vierte hasta 12 tazas de agua y presiona el botón “Brew”.

• El agua se calienta hasta que hierva. El vapor que se forma hace que el agua se rocíe sobre el café molido y, la infusión de café gotea a través del filtro y cae en la jarra.

Page 8: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Especificación de Mark IV

• La jarra se mantiene caliente por extensos períodos por un plato calefactor, el cual se activa sólo si hay café en la jarra.

• Si la jarra se retira del plato calefactor mientras está goteando el café, se detiene el flujo de agua, de forma tal que el café elaborado no se derrame sobre el plato calefactor.

Page 9: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Especificación • El siguiente hardware necesita ser controlado o

monitoreado:

• El elemento calefactor para el atomizador (boiler), puede activarse o desactivarse (on/off)

• Un sensor para el atomizador que, determina si hay agua o no. Puede adoptar 2 estados: boilerempty/boilernotempty

• El elemento calefactor para el plato, puede activarse o desactivarse (on/off)

• El sensor para el plato calefactor. Puede adoptar 3 estados: warmer empty (la jarra se quitó)/potempty/pot not empty

Page 10: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Especificación

• El botón Brew que se usa para iniciar el ciclo de elaboración del café.

• Tiene un indicador que se enciende cuando el ciclo de elaboración terminó y el café está listo

• Una válvula de alivio de presión que se abre para reducir la presión del atomizador. La caída de presión detiene el flujo de agua al filtro. Puede abrirse o cerrarse

Page 11: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Funciones de interface del hardware

• El hardware se completó.

• Los ingenieros de hardware proveyeron un API de bajo nivel en C, de forma tal de no tener que escribir código para los drivers de I/O a nivel de bits.

• El archivo runtime.h que proveyeron con la interfaz con el hardware:

Page 12: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de
Page 13: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Funciones de interface del hardware

• El switch en el plato calentador es un transductor de presión, se comporta como sigue

• P<T1 WarmerEmpty

• P>T1 && p<T2 potEmpty

• P>T2 potNotEmpty

Page 14: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Funciones de interface del hardware

Page 15: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Funciones de interface del hardware

Page 16: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Funciones de interface del hardware

Page 17: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Diseño del software de la Mark IV

• En el 1º libro Robert plantea ¿cómo comenzar el proceso de diseño?

• El autor postula como método útil es el intento de describir la secuencia de eventos derivados de un estímulo particular,

• por ejemplo: ¿Qué sucede cuando el usuario presiona el botón Brew?

• Esto es similar a crear un modelo dinámico aunque sin concentrarse en objetos y mensajes

Page 18: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Diseño

• El ciclo de elaboración de la infusión café no puede comenzar hasta que:

• haya agua en el atomizador,

• un recipiente vacío sobre el vaso calentador y,

• se presiona el botón Brew.

• Esto es:

• GetBoilerStatus retorna boilerNotEmpty,

• GetWarmerStatus retorna potEmpty y,

• GetBrewButtonStatus retorna BrewButtonPushed

Page 19: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Diseño

• El ciclo de elaboración comienza

• activando el elementocalefactor del atomizador,

• también habría que asegurarse que la válvula esté cerrada y,

• apagar el indicador lumínico.

• Esto implica invocar:

• SetIndicatorState(indicatorOff);

• SetReliefValveState(valveClosed);

• SetBoilerState(boilerOn);

Page 20: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Diseño

• A medida que el agua rocía el café molido, el recipiente comienza a llenarse y el plato calentador indica potNotEmpty,

• entonces habría que activar el elemento calentador del plato , es decir cuando

• GetWarmerStatus retorne potNotEmpty,

• se debería invocar SetWarmerState(warmerOn);

Page 21: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Diseño

• Cuando el atomizador está casi vacío GetBoilerStatus retornará boilerEmpty, entonces

• se debería desactivar el elemento calefactor del atomizador y,

• encender el indicador lumínico, indicando que el café está listo.

• Esto se logra invocando:

• SetBoilerState(boilerOff);

• SetIndicatorState(indicatorOn);

Page 22: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Diseño • Lejos de estar completo, podemos reconocer

el análisis anterior como un sistema que se mueve de estado a estado basado en un conjunto de eventos externos.

• Esto es claramente una máquina de estados finitos (FSM).

Page 23: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Diseño

• El autor, en su libro de C++, plantea que podría haberse detenido en la 1º FSM y codificarla en C o, en C++ sin objetos.

• Pero, se plantea que su compañía se propone diseñar otras cafeteras y, entonces piensan que la estrategia de plantear un diseño orientado a objetos es correcta.

• Invertir tiempo extra en el diseño y llegar a crear una librería de componentes reusables para facilitar la creación de productos similares

Page 24: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Hallar los objetos

• Uno de los primeros y más grandes problemas con los cuales se enfrenta el diseñador es descubrir los objetos, las principales abstracciones del problema.

• Hallar estos objetos puede ser una tarea muy complicada

• “The translation of a concept in the application area into a class in a design is not a simple mechanical operation. It often requires significant insights.” Stroustrup (1991)

Page 25: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Enfoque tradicional OO

• Buscar los sustantivos (y sustantivos adjetivados) en el problema y modelarlos con clases

• Buscar verbos en las especificaciones del problema y modelarlos como comportamientos de dichas clases (funciones)

• Describir las relaciones entre clases

Page 26: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Una solución común, aunque terrible

• El autor del libro al plantear este problema de diseño a sus alumnos encontró que la mayoría de los estudiantes ideó una solución tal como la que se verá en el siguiente diagrama de clases UML

Page 27: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de
Page 28: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Solución de diseño común, pero terrible

• En el diagrama se observa una clase central CoffeeMaker rodeada de “sirvientes” (minions) que controlan distintos dispositivos de hardware

• La clase CoffeeMaker contiene un Boiler, un WarmerPlate, un Button y una Light

• La clase Boiler contiene un BoilerSensor y un BoilerHeater

• La clase WarmerPlate contiene un PlateSensor y un PlateHeater

• Finalmene hay 2 clases bases , Sensor y Heater, que actúan como clases bases de Boiler y WarmerPlate, respectivamente.

Page 29: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Solución de diseño común pero terrible

• Hay algunos errores serios escondidos en este diagrama.

• Muchos de estos errores no se registran hasta que se intenta llevar a código este diseño, momento en el cual se manifiesta que el código es absurdo.

Page 30: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Faltan métodos

• El problema mayor del diagrama de clases anterior es una falta completa de métodos.

• Los programas tratan con comportamiento!

• ¿Dónde está el comportamiento en este diagrama?

• Los diseñadores al crear este diagrama sin métodos pueden estar particionando el software en algo que no sea el comportamiento (se basaron en el hardware)

Page 31: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Faltan métodos

• La partición del software que no se basa en comportamiento, casi siempre conduce a errores significativos.

• El comportamiento del sistema es el primer indicio para particionar el software

Page 32: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Clases vapor • Para poder apreciar qué tan pobremente se particionó este

diseño particular, consideremos los métodos que pondríamos en la clase Light

• Claramente un objeto de esta clase puede encenderse (on) o apagarse (off), por tanto podría implementarse así:

class Light{

public: static void on(){ SetIndicatorState(indicatorOn); } static void off(){ SetIndicatorState(indicatorOff); } };

Page 33: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Clases vapor

• Hay algunas cosas peculiares en la clase Light, en primer lugar no hay variables, esto es anormal puesto que, usualmente un objeto tiene alguna clase de estado que manipula.

• Segundo, los métodos on y off simplemente delegan a la función SetIndicatorState() del API,

• aparentemente la clase Light no es más que un adaptador de llamadas a funciones, realmente no está haciendo nada útil

Page 34: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Clases vapor

• ¿Porqué estas funciones miembro inline se declaran static?

• El sistema en tiempo de ejecución que fue dado por los ingenieros de hardware, no permite más de un atomizador, indicador, botón, etc.

• Por tanto no tiene sentido instanciar ninguna de las clases mencionadas puesto que, no puede haber más que una instancia de cada una de ellas, por lo cual,

• bien podríamos llamar a estas funciones como Light::on().

• Pero, ¿cual es la diferencia entre esto y simplemente llamar a SetIndicatorState(indicatorOn)? No mucha

Page 35: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Clases vapor

• El mismo razonamiento puede aplicarse a las clases Boiler, Button y WarmerPlate.

• Quizás hemos fallado en hallar las verdaderas abstracciones.

• Quizás deberíamos examinar más a fondo el problema y tratar de hallar las abstracciones subyacentes.

• Podríamos quitarlas del diseño sin cambiar para nada la lógica de la clase CoffeeMaker, la cual podría llamar directamente a las funciones del API, sin necesidad de hacerlo a través de adaptadores.

Page 36: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Clases vapor • Considerando todo esto hemos degradado

estas clases de su posición prominente en el diagrama de clases en meras variables sin mucha razón para existir. Por eso el autor las llama clases vapor

Page 37: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Abstracciones imaginarias

• Observemos las clases base Sensor y Heater. Habíamos visto que sus clases derivadas “venden humo” pero,

• ¿qué ocurre con estas clases? A simple vista parecen tener mucho sentido.

• Las abstracciones suelen ser engañosas, los humanos solemos verlas por todos lados pero, muchas de ellas no son apropiadas para ser convertidas en clases.

• Estas en particular, no tienen lugar en el diseño. ¿Quién las usa?

Page 38: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Abstracciones imaginarias • Ninguna clase del sistema realmente usa estas clases base. • Si nadie las usa ¿Cuál es el sentido para que existan? • A veces puede tolerarse una clase base que nadie usa, si

suministran código a sus derivadas pero, • en estas clases base no hay código, sólo métodos abstractos.

Oficialmente inútil

class Heater{ public: virtual void on()=0; virtual void off()=0; };

Page 39: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Abstracciones imaginarias • La clase Sensor es peor! • Al igual que Heater tiene sólo métodos abstractos y

ningún usuario. • Es peor porque, su único método tiene valores de

retorno ambigüos. En BoilerSensor retorna 2 valores posibles (boilerOn/boilerOff) pero, en WarmerPlateSensor retorna 3 valores posibles (warmerEmpty, potEmpty, potNotEmpty).

• No podemos especificar el contrato de Sensor, lo mejor que se puede hacer es retorna un entero, esto es bastante débil

class Sensor{ public: virtual int sense()=0; }

Page 40: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Abstracciones

• Lo que ocurrió es que, leído las especificaciones,

• hallado un conjunto de sustantivos probables,

• hecho inferencias acerca de sus relaciones y creado un diagrama de clases UML basado en este razonamiento,

• se las implementó y terminó quedando una clase todopoderosa CoffeeMaker rodeada de una serie de sirvientes jactanciosos.

• Bien podríamos programar esto en C!

Page 41: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Clases dioses

Page 42: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Clases dioses

• Son una mala idea.

• No es buena idea concentrar toda la inteligencia de un sistema en un solo objeto o en una sola función.

• Uno de los objetivos del diseño OO es la partición y distribución del comportamiento en muchas clases y muchas funciones.

• Resulta, sin embargo que, muchos modelos de objetos que parecen ser distribuidos son en realidad, el disfraz de la morada de los dioses

Page 43: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Clases dioses • El diagrama de clases visto es el perfecto

ejemplo. A primera vista parece que hubiese muchas clases con comportamiento interesante pero, profundizando en el código que implementarían dichas clases se halla que, sólo una tiene un comportamiento interesante: CoffeeMaker y el resto son clases vapor o abstracciones imaginarias

Page 44: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Análisis OO: Buscar las abstracciones subyacentes

• Resolver este problema de la cafetera es un ejercicio interesante en abstracción

• El truco es retroceder y separar los detalles de la naturaleza esencial.

• Olvidémonos de atomizadores, válvulas, calentadores, sensores y todos los pequeños detalles y concentrémonos en el problema subyacente.

• ¿Cuál es el problema?: ¿Cómo preparar café?

Page 45: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Análisis OO: Buscar las abstracciones subyacentes

• Pero ¿qué se necesita para preparar café? • Los ingenieros de hardware proveyeron un buen sistema en tiempo

de ejecución que nos permite llevar a cabo esta tarea, sin embargo, el mismo está completamente ligado a la solución del problema y no a la tarea real de preparar café.

• Por ejemplo, el propósito de la válvula es aliviar la presión en el atomizador, de forma tal que pare de rociar agua sobre el café molido pero, la abstracción subyacente no tiene nada que ver con válvulas, atomizadores o presión!

• La abstracción subyacente es simplemente controlar el rociado de agua sobre el café molido y, esta abstracción permanece válida independientemente de la solución de hardware.

• Los ingenieros de hardware podrían reemplazar la válvula y añadir una bomba de agua caliente y, esto no cambiaría la abstracción

Page 46: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de
Page 47: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Análisis OO: Buscar las abstracciones subyacentes

• La implementación de esta abstracción tiene algunas complejidades.

• Para rociar agua caliente, el elemento calefactor del atomizador tiene que activarse y, la válvula tiene que cerrarse.

• Para detener el rociado la válvula debe abrirse y, probablemente, se desee desactivar el elemento calefactor del atomizador puesto que, probablemente no se desee que la cafetera exude una gran columna de vapor (salvo que se quisiera usar como humidificador)

Page 48: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Análisis OO: Buscar las abstracciones subyacentes

• Cuando complejidades como estas pueden ocultarse por una simple abstracción, se gana terreno sobre la complejidad del problema, no se elimina la complejidad sino que se la maneja!,

• queda aislada dentro de la abstracción, de la cual no puede escapar para contaminar el resto de la aplicación

• ¿Qué acerca del atomizador? ¿Representa una abstracción separada de esta?

• Es irrelevante que la cafetera lo tenga mientras que, nuestra abstracción entregue agua caliente. Sin embargo, el atomizador puede bien aparecer nuevamente, como una abstracción de segundo nivel dentro de esta que el autor llama HotWaterSource

Page 49: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Análisis OO: Búscar las abstracciones subyacentes

• La más simple y más común solución a este problema es: – Rociar agua caliente sobre café molido y,

– Obtener la infusión resultante en alguna clase de recipiente

• ¿De dónde sacamos el agua caliente? Llamémosle HotWaterSource

• ¿Dónde recogemos la infusión? Llamémosle ContainmentVessel

• Estas 2 abstracciones ¿son realmente clases?

Page 50: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Asignar responsabilidades a las abstracciones

• Asignar responsabilidades a las abstracciones escogidas, a veces, es tan difícil como hallar los objetos

• O, quizás es más difícil, como señala Booch (1991), “This step is much harder than the first and takes much longer. This is the phase in which there may be fierce debates, wailing and gnashing of teeth, and general name-calling during design reviews. Finding classes and objects is the easy part; deciding upon the protocol of each object is hard.”

Page 51: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Asignar responsabilidades a las abstracciones

• Sería bueno desacoplar las abstracciones halladas cada una de la otra,

• dividiendo las responsabilidades y manteniéndolas separadas.

• Sin embargo, esto puede ser todo un desafío

Page 52: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Una posible solución

• ¿Qué comportamiento de HotWaterSource puede capturarse en software?

– Calentar el agua, rociarla sobre el café molido para que gotee sobre el recipiente

– Podemos imaginar al atomizador, válvula y sensor del atomizador jugando el rol de HotWaterSource

Page 53: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Una posible solución

• ¿ContainmentVessel hace algo que el software podría controlar?

– Sería responsable de mantener caliente la infusión de café contenida en el recipiente; también permitiría conocer si queda café o no en el recipiente y, si está o no el contenedor sobre el plato calentador

– Podemos imaginar al plato calentador y a su sensor jugando el rol de ContainmentVessel

Page 54: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Cables cruzados

Page 55: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Cables cruzados

• ¿Cómo se podría capturar la anterior discusión en un diagrama de clases UML?

• Un posible esquema donde HotWaterSource y ContainmentVessel son representados como clases y asociadas por el flujo del café (infusión)

Page 56: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Cables cruzados

• La asociación muestra un error que los iniciados en OO suelen cometer.

• La asociación se realizó en base a algo físico acerca del problema en vez del comportamiento del software de control.

• El hecho que el café fluye del HotWaterSource a ContainmentVessel es totalmente irrelevante para la asociación entre estas dos clases

Page 57: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Cables cruzados

• Por ejemplo, ¿qué si ContainmentVessel le indica a HotWaterSource cuando comenzar y cuándo detener el flujo del agua caliente hacia el recipiente?

Page 58: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Cables cruzados • ContainmentVessel envía el mensaje start a

HotWaterSource.

• Esto indica que la asociación es al revés. HotWaterSource no depende para nada de ContainmentVessel.

• Mas bien, ContainmentVessel depende de HotWaterSource

Page 59: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Cables cruzados

• La lección aquí es: las asociaciones son los caminos a través de los cuales se envían mensajes a los objetos, no tienen nada que ver con el flujo de objetos físicos.

• El hecho que el agua caliente fluya del atomizador al recipiente no indica que debería haber una asociación de HotWaterSource hacia ContainmentVessel

• El autor llama cables cruzados a este error particular debido a que la conexión entre las clases se cruzaron entre los dominios lógicos y los dominios físicos

Page 60: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

La interfaz de usuario de la cafetera • Está claro que algo está faltando en nuestro modelo de

la cafetera. • No hay ninguna forma para que el humano interactúe

con el sistema. En algún lado nuestro sistema tiene que atender los comandos del humano.

• Igualmente el sistema debe ser capaz de reportar su estado a los propietarios humanos.

• Ciertamente, esta cafetera tiene hardware dedicado a este propósito. El botón y la luz sirven como interfaz de usuario (UI)

• Por tanto, se añadirá la clase UserInterface a nuestro modelo de cafetera.

• Esto proporciona una triada de clases interactuando para preparar café bajo la dirección de un usuario

Page 61: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Casos de uso

Page 62: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Casos de uso

• Dadas estas 3 clases, ¿Cómo se comunican sus instancias?

• Veamos los siguientes casos de uso para ver si descubrimos cuál es el comportamiento de estas clases

Page 63: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 1: El usuario pulsa el botón Brew

• ¿Qué objeto (de qué clase) detecta el hecho que el usuario presiona el botón Brew?

• Claramente debe ser el objeto UserInterface

• ¿Qué hace este objeto cuando se pulsa este botón?

Page 64: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 1: El usuario pulsa el botón Brew

• Nuestro objetivo es iniciar el flujo de agua caliente.

• Sin embargo, antes de hacer eso, hay que asegurarnos que ContainmentVessel está listo para aceptar café.

• También sería mejor asegurarse que HotWaterSource esté lista.

• Para esta cafetera esto significa asegurar que el atomizador está lleno y que, el recipiente está vacío y situado sobre el plato calentador.

Page 65: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 1: El usuario pulsa el botón Brew

• De forma tal que, la primera acción que nuestro objeto UserInterface realizar es enviar un mensaje a HotWaterSource y ContainmentVessel encuestándolos para ver si están listos.

Page 66: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 1: El usuario pulsa el botón Brew

• Si cualquiera de estas peticiones retorna false entonces no debería comenzar a prepararse el café.

• El objeto UserInterface puede hacerse cargo de informarle al usuario de esta situación (requerimiento denegado). En el caso de esta cafetera podria hacer titilar la luz varias veces

• Si ambas peticiones retornan true debe comenzar el flujo de agua caliente.

Page 67: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 1: El usuario pulsa el botón Brew

• Probablemente el objeto UserInterface enviaría un mensaje Start al objeto HotWaterSource, éste hará lo necesario para proveer agua caliente que se rociará sobre el café.

• En el caso de esta cafetera se cerrará la válvula y activará (on) el elemento calefactor del atomizador.

• El escenario completo de este caso de uso representado en un diagrama de colaboración UML:

Page 68: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 1: El usuario pulsa el botón Brew

Page 69: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 2: el recipiente no está listo

• En las especificaciones de la cafetera sabemos que el usuario puede retirar el recipiente del plato calentador durante la elaboración del café.

• ¿Qué objeto detecta esta situación?

• Sin duda será el ContainmentVessel.

• Según los requerimientos, cuando esto sucede, hay que detener el flujo de café.

Page 70: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 2: el recipiente no está listo

• Por tanto, ContainmentVessel debe ser capaz de comunicarle a HotWaterSource que pare de enviarle agua caliente.

• Igualmente debe ser capaz de informarle que comience nuevamente a producir café cuando el recipiente se repone sobre el plato calentador.

• En la figura se añaden nuevos métodos:

Page 71: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 2: el recipiente no está listo

Page 72: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 3: Preparación del café completa

• En algún momento se habrá terminado la elaboración de la infusión café y se deberá cortar el flujo de agua caliente.

• ¿Cuál de los objetos sabe cuando la preparación se completó?

• En el caso de esta cafetera el sensor en el atomizador nos indica que el atomizador está vacío, o sea, es detectado por el objeto HotWaterSource

Page 73: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Pensando en reusar las abstracciones

Page 74: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Pensando en reusar las abstracciones

Page 75: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Pensando en reusar las abstracciones

• https://sprudge.com/5-ridiculous-coffee-combination-brewers-just-gotta-see-43583.html

Page 76: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Pensando en reusar las abstracciones

Page 77: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 3: Preparación del café completa

• Sin embargo, no es difícil imaginar una cafetera en la cual ContainmentVessel pueda detectar que la preparación del café está lista,

• ¿Qué si la cafetera estaría conectada a la red de agua y por tanto tendría un suministro infinito de agua?

• ¿Qué si el agua fuese calentada por un generador de microondas intenso como si fluyese a través de los tubos de un recipiente térmicamente aislado?

• ¿Qué si el recipiente tendría una espita desde donde el usuario obtendría su café?

• En este caso el recipiente tendría un sensor que sabría si éste está lleno y que, por tanto debería cortarse el flujo de agua caliente

Page 78: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 3: Preparación del café completa

• El punto está en el dominio abstracto de HotWaterSource y ContainmentVessel, ninguno de los 2 es un candidato convincente para detectar que se terminó la elaboración del café.

• La solución del autor es ignorar este tema, asumiendo que cualquiera de los objetos puede informarle a los otros que la elaboración está lista.

Page 79: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 3: Preparación del café completa

• En nuestro modelo ¿Cuáles objetos necesitan conocer que la preparación está lista?

• Ciertamente UserInterface necesita saberlo desde que esta cafetera, cuando esto ocurre, debe encender una luz.

• Está claro que también HotWaterSource necesita saber que la preparación se terminó para detener el flujo de agua caliente.

• ¿ContainmentVessel necesita saberlo? ¿Hay algo especial que necesita hacer o controlar una vez que la preparación se terminó?.

Page 80: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 3: Preparación del café completa

• En esta cafetera, hay que detectar que el recipiente vacío se coloca nuevamente en el plato calentador, indicando que el usuario se ha servido lo último que quedaba del café, con lo cual debería apagarse la luz.

• Por tanto ContainmentVessel necesita saber que la preparación está lista.

• De hecho, el mismo argumento puede usarse para decir que UserInterface enviaría el mensaje Start al ContainmentVessel cuando comienza la preparación

Page 81: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 3: Preparación del café completa

• La figura muestra los nuevos mensajes. Puede notarse que HotWaterSource o ContainmentVessel, pueden enviar el mensaje Done

Page 82: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 4: el café se terminó

• Esta cafetera apaga la luz cuando la preparación está lista y se coloca un recipiente vacío sobre el plato calentador.

• Claramente en nuestro modelo ContainmentVessel detectaría esta situación y tendría que enviar un mensaje a UserInterface

• La figura muestra el diagrama completo de colaboración y, a partir de este diagrama, se puede dibujar un diagrama de clases con todas las asociaciones. Este diagrama no depara sorpresas

Page 83: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de
Page 84: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de
Page 85: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Implementando el modelo abstracto

• Nuestro modelo de objetos está razonablemente bien particionado.

• Tenemos 3 áreas distintas de responsabilidad, cada una de ella parecen estar enviando y recibiendo mensajes en forma balanceada.

• No parecen ser ni clases dioses ni clases vapor.

• Hasta aquí todo bien pero,

• ¿Cómo implementamos la cafetera en esta estructura?

• ¿Implementamos los métodos de estas 3 clases para invocar el API? Esto sería una verdadera lástima!

Page 86: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Implementando el modelo abstracto

• Hemos capturado la esencia de lo que implica elaborar café.

• Sería un lamentablemente pobre diseño si, vinculáramos esa esencia a nuestra cafetera MarkIV.

• El autor propone una nueva regla: ninguna de estas 3 clases debe saber nada acerca de la cafetera Mark IV.

• Este es el Principio de Inversión de la Dependencia (DIP). No vamos a permitir que la política de alto nivel de hacer café de este sistema dependa de detalles de la implementación de bajo nivel

Page 87: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Principio de inversión de dependencia (DIP)

Page 88: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Un ejemplo simple

Page 89: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Un ejemplo simple

Page 90: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Ejemplo completo de Robert Martin

• DIP puede aplicarse siempre que una clase envía un mensaje a otra.

• Por ejemplo, considere el caso de un objeto Button y uno Lamp

• El objeto Button sensa el entorno externo, puede determinar si un usuario lo ha presionado o no,

• sin importar el mecanismo de sensado. • Podría ser el ícono de un botón en una GUI, un botón

físico pulsado por un humano o aún un detector de movimiento en un sistema de seguridad hogareño

• El botón detecta que el usuario lo ha activado o desactivado

Page 91: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Ejemplo completo de Robert Martin

• El objeto Lamp afecta el entorno externo. Cuando recibe un mensaje TurnOn enciende una luz de algún tipo, cuando recibe el mensaje TurnOff se apaga dicha luz,

• el mecanismo físico no es importante.

• Podría ser un indicador LED en un aparato, una luz de vapor de mercurio en un estacionamiento o aún el laser de una impresora laser.

Page 92: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Ejemplo completo de Robert Martin

• ¿Cómo podemos diseñar un sistema donde el objeto Button controle al objeto Lamp?

• En la figura siguiente se observa un diseño naif.

• El objeto Button simplemente envía los mensajes TurnOn/TurnOff al objeto Lamp.

• Para facilitar esto la clase Button usa una relación “contiene” para mantener una instancia de la clase Lamp.

Page 93: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Ejemplo completo de Robert Martin

Page 94: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Ejemplo completo de Robert Martin

• Veamos el código en C++ que resulta de este modelo.

• La clase Button depende directamente de la clase Lamp, el módulo button.cc incluye el módulo lamp.h.

• Esta dependencia indica que la clase Button debe cambiar o, por lo menos recompilarse, siempre que cambie la clase Lamp.

• Asimismo, no será posible reusar la clase Button para control un objeto Motor.

Page 95: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Ejemplo completo de Robert Martin

Page 96: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Ejemplo completo de Robert Martin

• Se viola el DIP, la política de alto nivel de la aplicación no se separó de los módulos de bajo nivel;

• la abstracción no se separó de los detalles.

• Sin tal separación las políticas de alto nivel automáticamente dependen de los módulos de bajo nivel y,

• las abstracciones automáticamente dependen de los detalles

Page 97: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Ejemplo completo de Robert Martin

• ¿Qué son las políticas de alto nivel? Las abstracciones que forman la base de la aplicación, las verdades que no varían cuando se cambian los detalles.

• En este ejemplo, las abstracción de base es detectar una acción on/off de un usuario y transmitir esa acción al objeto “target”.

• El mecanismo usado para detectar esa acción es irrelevante!

• Cuál es el objeto target también es irrelevante! • Estos son detalles que no impactan la abstracción

Page 98: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Ejemplo completo de Robert Martin

• Para conformar el principio de DIP debemos aislar esta abstracción de los detalles del problema.

• Debemos dirigir las dependencias del diseño de forma tal que los detalles dependan de abstracciones.

• La siguiente figura muestra tal diseño, donde se aísla la abstracción de la clase Button

Page 99: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Ejemplo completo de Robert Martin

Page 100: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Ejemplo completo de Robert Martin

• En el código puede observarse que las políticas de alto nivel quedan enteramente capturada dentro de la clase abstracta Button.

• La clase Button no conoce nada sobre el mecanismo de detección de las acciones del usuario (el método Button::Detect() es un “template” que hace uso de la función virtual pura Button::GetState()),

• ni tampoco sabe nada acerca de la lámpara. • Estos detalles están aislados dentro de las clases

derivadas concretas: ButtonImplementation y Lamp.

Page 101: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Ejemplo completo de Robert Martin

Page 102: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Ejemplo completo de Robert Martin

• La política de alto nivel de este código es reusable con cualquier clase de botón y, con cualquier clase de dispositivo que necesite controlarse,

• además de no ser afectada por los cambios de los mecanismos de bajo nivel.

• Por tanto es robusto frente a los cambios y reusable

Page 103: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Ejemplo completo de Robert Martin • Se podría presentar una queja legítima acerca de

este diseño/código. El dispositivo controlado por el botón debe derivarse de la clase ButtonClient. ¿Qué ocurre si la clase Lamp pertenece a una librería de terceros y no puede modificarse su código fuente.

• En la siguiente figura se usa una clase “adaptadora” para conectar un objeto Lamp de terceros al modelo.

• La clase LampAdapter simplemente traslada los mensajes TurnOn/TurnOff (virtuales puros) heredados de ButtonClient en cualquier mensaje que la clase Lamp necesite ver

Page 104: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Ejemplo completo de Robert Martin

Page 105: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Implementando el modelo abstracto

• Entonces, ¿Cómo creamos la implementación de la cafetera Mark IV?

• Miremos todos los casos de uso nuevamente ahora desde el punto de vista de la Mark IV

• Veremos cómo aparecen todas estas ideas de diseño a la luz de la realidad inyectada por el código y, tal vez haga que el diseño se modifique

Page 106: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 1: El usuario pulsa el botón Brew

• Mirando nuestro modelo, ¿Cómo sabe UserInterface que se pulsó el botón Brew?

• Claramente, debe llamar a la función del API getBrewButtonStatus().

• ¿Dónde se invocaría esta función? Nosotros decretamos que UserInterface no puede saber nada del API.

• ¿Entonces dónde iría esta invocación? • Aplicaremos el DIP y pondremos esta invocación

dentro de una función miembro de una clase derivada de UserInterface

Page 107: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 1: El usuario pulsa el botón Brew

Page 108: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 1: El usuario pulsa el botón Brew

• Se deriva M4UserInterface de UserInterface y, en M4UserInterface se pone el método checkButton().

• Cuando se invoca a esta función, ella llamará a la función del API GetBrewButtonState().

• Si el botón Brew se presionó, se invoca a la función protected startBrewing(), miembro de UserInterface

Page 109: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 1: El usuario pulsa el botón Brew

class M4UserInterface: public UserInterface{

private:

void checkButton(){

int buttonStatus=GetBrewButtonStatus();

if(buttonStatus==brewButtonPushed)

startBrewing(); //protected

}

};

Page 110: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 1: El usuario pulsa el botón Brew

class UserInterace{ private: // son clases abstractas no puedo instanciar objetos, uso punteros o & HotWaterSource* hws; ContainmentVessel* cv; public: //implementación incompleta void done(); void complete(); protected: void startBrewing(){

if(hws->isReady() && cv->isReady()){ hws->start(); cv->start(); } } };

Page 111: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 1: El usuario pulsa el botón Brew

• Se pueden estar preguntando, ¿porqué se crea método startBrewing() ?

• ¿Porqué no se llama directamente a las funciones start() directamente desde M4UserInterface?

• La razón es simple pero significativa. Las verificaciones isReady() y las consiguientes llamadas a start() de HotWaterSource y ContainmentVessel son políticas de alto nivel que la clase UserInterface posee.

Page 112: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Caso de uso 1: El usuario pulsa el botón Brew

• Este código es válido independientemente de si estamos implementando la MarkIV, por lo tanto, no debería acoplarse a la derivada MarkIVUserInterface.

• El autor aclara que hará esta misma distinción una y otra vez en este ejemplo.

• Él mantiene tanto código como se puede en las clases de alto nivel;

• el único código que pondrá en las clases derivadas es aquél que es directamente e inexorablemente asociado a la MarkIV

Page 113: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Implementando las funciones isReady

• ¿Cómo se implementan los métodos isReady() de HotWaterSource y ContainmentVessel?

• Debería quedar claro que son realmente métodos abstractos.

• Las correspondientes clases derivadas M4HotWaterSource y M4ContainmentVessel los implementarán llamando a las funciones del API apropiadas

Page 114: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Implementando las funciones isReady

Page 115: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Implementando las funciones isReady

class M4HotWaterSource: public HotWaterSource{

public:

bool isReady(){

int boilerStatus=GetBoilerStatus();

return boilerStatus==boilerNotEmpty;

}

};

Page 116: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Implementando las funciones isReady

class M4ContainmentVessel:public ContainmentVessel{

public:

bool isReady(){

int plateStatus=GetWarmerPlateStatus();

return plateStatus==potEmpty;

}

};

Page 117: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Implementando las funciones start

• El método start() de HotWaterSource es un método abstracto que,

• es implementado dentro por su clase derivada M4HotWaterSource para invocar a las funciones del API que cierra la válvula y activa el elemento calefactor del atomizador.

Page 118: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Implementando las funciones start

//public void M4HotWaterSource::start(){ setReliefValveState(valveClosed); setBoilerState(BoilerOn); } • El método start() de ContainmentVessel es mucho

más interesante. • La única acción que M4ContainmentVessel necesita

realizar es, recordar el estado de elaboración (brewing) del sistema (mediante variables de estado).

• Como veremos posteriormente, esto permitirá responder correctamente cuando el recipiente se coloca o quita del plato calentador

Page 119: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Implementando las funciones start class M4ContainmentVessel:public ContainmentVessel{ private: bool isBrewing; public: bool isReady(){ int plateStatus=GetWarmerPlateStatus(); return plateStatus==potEmpty;} void start(){ isBrewing=true; } };

Page 120: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

¿Cómo se invocará checkButton?

• ¿Cómo llega el flujo de control a un lugar donde la función del API GetBrewButtonStatus() pueda invocarse?,

• En efecto, ¿Cómo llega el flujo de control donde se puedan detectar los sensores?

• Se adopta el enfoque de usar polling.

• Aquí modificaremos un poco la solución planteada en Java (usan interfaces) y para no usar herencia múltiple en C++

Page 121: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

¿Cómo se invocará checkButton?

• Las 3 clases derivadas tienen sensores, por tanto,

• en cada una implementaremos una función poll() que represente la noción de que esta clase de alguna forma debe ganar el control del procesador para detectar algún evento relacionado con estos sensores,

• las cuales serán llamadas repetidamente, de forma tal que, estas clases puedan chequear si tal evento ocurrió

Page 122: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

¿Cómo se invocará checkButton?

• Una función main() tomó el lugar de la clase CoffeeMaker (dios)

• La función main() estará en un archivo CoffeeMaker.cpp y simplemente instanciará los 3 componentes de las clases derivadas M4,

• luego invocará funciones init() sobre esos 3 objetos creados, para comunicar cada componente con el otro y,

• finalmente esperará en un lazo infinito invocando al método poll() de cada componente, sucesivamente

Page 123: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

¿Cómo se invocará checkButton?

• Luego de lo visto, tenemos claro que checkButton() será sustituida por un método private:

void M4UserInterface::poll(){

int buttonStatus=GetBrewButtonStatus();

if(buttonStatus==brewButtonPushed)

startBrewing();

}

Page 124: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Completando el código

• El mismo razonamiento empleado en las secciones anteriores, puede repetirse para cada uno de los componentes de la cafetera.

Page 125: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

UserInterface class UserInterface{ private: //clases abstractas, no puedo instanciar objetos, puedo usar * o & HotWaterSource* hws; ContainmentVessel* cv; protected: bool isComplete; void startBrewing(){ if(hws->isReady() && cv->isReady()){ isComplete=false;// cambia de true a false hws->start(); cv->start(); } } //sigue

Page 126: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

UserInterface

public:

UserInterface():hws(0),cv(0){

isComplete=true;

}

void init(HotWaterSource* hws, ContainmentVessel* cv){

this->hws=hws;

this->cv=cv;

}//sigue

Page 127: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

UserInterface

void complete(){

isComplete=true;

completeCycle();

}

/*estímulos externos*/

virtual void done()=0;

virtual void completeCycle()=0;

};//fin UserInterface

Page 128: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

M4UserInterface /*implementa el modelo de control de la UI de la cafetera MarkIV*/

class M4UserInterface: public UserInterface{

public:

void poll(){

int buttonStatus=GetBrewButtonStatus();

if(buttonStatus==brewButtonPushed)

startBrewing();

}

//sigue

Page 129: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

M4UserInterface /*estímulos externos*/

void done(){

SetIndicatorState(indicatorOn);

}

void completeCycle(){

SetIndicatorState(indicatorOff);

}

};//fin clase M4UserInterface

Page 130: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

HotWaterSource

class HotWaterSource{ private: //clases abstractas, no puedo instanciar objetos, puedo usar * o & UserInterface* ui; ContainmentVessel* cv; protected: bool isBrewing; //método protected void declareDone(){ ui->done(); cv->done(); isBrewing=false; } //sigue

Page 131: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

HotWaterSource public:

HotWaterSource():ui(0), cv(0){

isBrewing=false;

}

void init(UserInterface* ui, ContainmentVessel *cv){

this->ui=ui;

this->cv=cv;

}

void start(){

isBrewing=true;//cambia de false a true

startBrewing();

}//sigue

Page 132: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

HotWaterSource

void done(){

isBrewing=false;

}

virtual boolean isReady()=0;

virtual void startBrewing()=0;

virtual void pause()=0;

virtual void resume()=0;

};//fin clase HotWaterSource

Page 133: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

M4HotWaterSource

class M4HotWaterSource:public HotWaterSource{

public:

void isReady(){//hay agua en el atomizador

int boilerStatus=GetBoilerStatus();

return boilerStatus==boilerNotEmpty;

}

void startBrewing(){//spray

SetReliefValveState(valveClosed);

SetBoilerState(boilerOn);

}

Page 134: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

M4HotWaterSource

void poll(){ int boilerStatus=GetBoilerStatus(); if(isBrewing){ if(boilerStatus==boilerEmpty){//stop spray SetBoilerState(boilerOff); SetReliefValveState(valveClosed); declareDone(); } } }

Page 135: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

M4HotWaterSource

void pause(){

SetBoilerState(boilerOff);

SetReliefValveState(valveOpen);

}

void resume(){

SetBoilerState(boilerOn);

SetReliefValveState(valveClosed);

}

};//fin clase M4HotWaterSource

Page 136: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

ContainmentVessel class ContainmentVessel{

private:

//clases abstractas, no puedo instanciar objetos, puedo usar * o &

UserInterface* ui;

HotWaterSource* ws;

Page 137: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

ContainmentVessel

protected:

bool isBrewing; bool isComplete; //funciones miembro protected void declareComplete(){ isComplete=true; ui->complete(); } void containerAvailable(){ hws->resume(); } void containerUnavailable(){ hws->pause(); }

Page 138: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

ContainmentVessel public:

ContainmentVessel():ui(0),hws(0){

isBrewing=false;

isComplete=true;

}

void init(UserInterface* ui, HotWaterSource* hws){

this->ui=ui;

this->hws=hws;

}

void start(){

isBrewing=true;

isComplete=false;

}

void done(){

isBrewing=false;

}

virtual bool isReady()=0;

};//fin clase ContainmentVessel

Page 139: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

M4ContainmentVessel class M4ContainmentVessel:public ContainmentVessel{ private: int lastPotStatus; //métodos privados void handleBrewingEvent(int potStatus){ if(potStatus==potNotEmpty) containerAvailable(); SetWarmerState(warmerOn);} else if(potStatus==warmerEmpty){//retiraron el recipiente containerUnavailable(); SetWarmerState(warmerOff);} else{//potStatus==potEmpty, recipiente vacío, sin café containerAvailable(); SetWarmerState(warmerOff);} } } //sigue private

Page 140: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

M4ContainmentVessel

//sigue private: void handleIncompleteEvent(int potStatus){ if(potStatus==potNotEmpty){ SetWarmerState(warmerOn);} else if(potStatus==warmerEmpty){ SetWarmerState(warmerOff);} else{//potStatus==potEmpty, brewingComplete setWarmerState(warmerOff); declareComplete(); } }

Page 141: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

M4ContainmentVessel

public: M4ContainmentVessel(){ lastPotStatus=potEmpty;} bool isReady(){ int plateStatus=GetWarmerPlateStatus(); return plateStatus==potEmpty; }

Page 142: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

M4ContainmentVessel

void poll(){ int potStatus=GetWarmerPlateStatus(); if(potStatus!=lastPotStatus){ if(isBrewing){ handleBrewingEvent(potStatus);} else if(isComplete==false){ handleIncompleteEvent(potStatus);} lastPotStatus=potStatus; } } }//fin clase M4ContainmentVessel

Page 143: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

CoffeMaker.cpp int main(){ /*punteros a las clases base para que funcione el polimorfismo, con las funciones virtuales*/ UserInterface* uiA=new M4UserInterface(); HotWaterSource* hwsA=new M4HotWaterSource(); ContainmentVessel* cvA=new M4ContainmentVessel(); /*para poder invocar a poll(), no es miembro de las clases base*/ M4UserInterface* ui=dynamic_cast<M4UserInterface*> uiA; M4HotWaterSource* hws=dynamic_cast<M4HotWaterSource*>hwsA; M4ContainmentVessel* cv=dynamic_cast<M4ContainmentVessel*>cvA; ui->init(hws,cv); hws->init(ui,cv); cv->init(ui, hws); while(true){ ui->poll(); hws->poll(); cv->poll(); } }//fin main

Page 144: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Beneficios de este diseño

• A pesar la naturaleza trivial de este problema, este diseño muestra características muy buenas.

• Hay 3 clases que mantienen las políticas de alto nivel de la cafetera, estas abstracciones están completamente aisladas de los detalles.

• Son clases abstractas que no saben nada de botones, luces, válvulas, sensores ni ningún otro elemento detallado de la cafetera.

• En la misma línea, las clases derivadas son dominadas por estos detalles

Page 145: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Beneficios de este diseño

Page 146: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Conclusiones

• Los buenos diseños OO comprenden buenos modelos dinámicos y buenos modelos estáticos

• Los buenos modelos dinámicos describen los comportamientos demandados por los requerimientos de las especificaciones

• Los buenos modelos estáticos apoyan esas dinámicas mientras que permiten separar el diseño en componentes reusables

Page 147: Cafetera eléctrica OO - dsi.fceia.unr.edu.ar©ctrica_OO.pdf · Funciones de interface del hardware •El hardware se completó. •Los ingenieros de hardware proveyeron un API de

Beneficios de este diseño

• Estas 3 clases abstractas podrían reutilizarse para muchas clases de máquinas de café.

• Fácilmente podríamos usarla en una cafetera conectada a la red de agua y que, use un tanque y una espita.

• Parece probable que, también podamos usarlo para una máquina expendedora de café, en una elaborada de té automática o aún en una máquina de sopas