Patrón Observador para Sistemas Embebidos, parte I

En esta ocasión voy a exponer una implementación del patrón Observador orientado a sistemas embebidos que carecen de memoria dinámica. En sistemas embebidos con procesadores con hasta 256 KB en RAM es difícil tener un manejador de memoria dinámica, y al mismo tiempo tampoco se tiene una implementación decente (en términos de tamaño) de la STL. El patrón Observador se escribe en forma muy elegante haciendo uso de la STL, pero como lo he mencionado, asumiremos que nuestro sistema no cuenta ni con memoria dinámica ni con dicha librería.

Este patrón requiere una lista de observadores que vamos a implementar con un típico arreglo estático de N elementos. De todos modos es difícil encontrar un escenario para nuestros pequeños procesadores (pequeños en términos de RAM, no de potencia de cálculo) donde tengamos la necesidad de hacer crecer o disminuir la cantidad de elementos del arreglo.

Así, yo llamaría a esta implementación del patrón como “Patrón observador con implementación estática”, que tiene como primer consecuencia que no exista el método Remove () o Detach() para eliminar entradas de la lista de observadores.

El primer uso que le voy a dar a dicha implementación, y por lo cual no requiero el método Remove (), es tener una lista de timers, cada uno independiente de los demás. Se le notificará a los observadores (las tareas que esperan por el transcurso de un intervalo de tiempo) cada vez que se produzca un tick del sistema. Cada timer será una unidad autocontenida.

Esta primera implementación tampoco utiliza clases abstractas. Aún no, porque estoy haciendo una prueba de concepto. En las siguientes partes ya lo haré como lo ordenan los cánones.

En el código presentado a continuación utilicé al flujo cout con fines de depuración únicamente. También el código puede adaptarse fácilmente a usos diferentes del que se me ocurrió.

#include <iostream>

using namespace std;


class Observer
{
public:
    void Update ();


    /*-----------------------------------------------------------------------------
     *  A partir de aquí la clase concreta hace lo que quiera
     *-----------------------------------------------------------------------------*/
    Observer (int newVal = 0);
    void Print () { cout << "Val: " << this->val << endl; }

private:
    int val;
};

void Observer::Update ()
{
    cout << "El observador está siendo notificado ...\n";
    this->val++;
}

Observer::Observer (int newVal) : val (newVal)
{

}


class Subject
{
public:
    Subject ();

    bool Add (Observer * newObserver);
    void Notify ();

private:
    Observer * list[5];
    // lista de observadores
    
    int index;
    // índice a la siguiente entrada disponible en la lista de observadores
};

Subject::Subject () : index (0)
{
    for (int i = 0; i < 5; ++i) {
        this->list[i] = NULL;
    }
}

bool Subject::Add (Observer * newObserver)
{
    if (this->index > 4) { return false; }
    // ya no caben más observadores

    this->list[this->index] = newObserver;
    this->index++;

    return true;
}

void Subject::Notify ()
{
    for (int i = 0; i < 5; ++i) {
        if (this->list[i] == NULL) { continue; }

        this->list[i]->Update ();
        // solamente avisa de una actualización, no envía datos
    }
}

/*
 * Driver program
 */
int main()
{
    Subject sujeto;
    Observer observador1;
    Observer observador2 (10);

    sujeto.Add (&observador1);
    sujeto.Add (&observador2);

    for (int i = 0; i < 6; ++i) {
        sujeto.Notify ();
    }

    observador1.Print ();
    observador2.Print ();

}

Un saludo y quedo a la espera de sus comentarios.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s