Modelo Vista Controlador

Este concepto se repite muchas veces en cuanto comenzamos a trabajar en Cocoa. La idea inicial es simple: separar lo que ve el usuario de los interiores de la aplicación. En este caso se hace en tres elementos:

  • Modelo: son los datos con los que vamos a trabajar, incluyendo todo el conjunto de reglas que tienen que respetar, cómo pueden modificarse y cómo se accede a estos datos.
  • Vista: es la representación de los datos y recoger la interacción con el usuario.
  • Controlador: es la parte que toma decisiones, analiza la entrada que ha hecho el usuario y actúa en consecuencia.

Hasta aquí la cosa es clarísima, podemos ver más detalles en Wikipedia: Modelo Vista Controlador, en Proactiva.com: Patrón “Modelo Vista Controlador” y en Ejemplos Java y C/linux: Separación modelo vista controlador. El problema viene cuando se intenta representar la relación entre los tres elementos: no he encontrado dos esquemas iguales. Peor aún, a mi que soy un novato en esto de los objetos y Objective-C no he visto claro en ninguna parte explicado cuando se crean los objetos y como interactúan entre ellos. Pero me parece que no soy el único he visto en la red larguísimas discusiones sobre cómo tienen que ser las relaciones. De esta forma lo que viene es cómo yo he entendido este esquema y cómo podemos utilizarlo en un programa para Mac OS X.

Las relaciones MVC

Relaciones Modelo Vista ControladorEl modelo no tiene que acceder ni a la vista ni al controlador. La vista tiene que poder acceder al modelo (obviamente para representarlo) y al controlador (para enviar las entradas que hace el usuario). Y el controlador ha de acceder al modelo (para conocer los datos y eventualmente pedir el cambio de estos) y a la vista para indicar los cambios en los datos.

Un ejemplo MVC

Muy bien si has entendido que es eso de Modelo-Vista-Controlador tienes mucho avanzado, pero eso ¿Cómo se aplica a un programa en Cocoa?Para ello me preparado un pequeño programa que simplemente mostrará unas rectas por pantalla, una recta cada vez según las indicaciones del usuario. El esquema es el siguiente:MVC Recta, esquema del programaVamos a crear tres clases, cada una de ellas nos representará a un elemento del trío MVC. Y esta vez el trabajo importante lo haremos con InterfaceBuilder.

1. Creación de las clases

Una vez creado el proyecto (¿hace falta explicar cómo?)se accede al programa Interface Builder. En este programa creamos tres clases (dentro de la pestaña classes de la ventana MainMenu.nib). MVCControl y MVCRecta que serán subclases de NSObject y MVCVista que será subclase de NSView. Recordad del artículo anterior que necesitábamos una subclase de NSView para poder dibujar.Una vez creada hacer falta añadir una instancia de las dos primeras a nuestro programa (recordar que se hace seleccionando la clase y luego con el menú Classes | Instantiate…).InstanciasAquí estaba una de mis mayores preocupaciones: ¿Cuando se crea el objeto de la clase MVCRecta o MVCControl? No veía por ninguna parte un método alloc, ni init, ni nada por el estilo. Lo que pasa es que el sistema nos oculta todo el montón de trabajo que hace cuando se inicia un programa. Es en el momento de iniciar el programa cuando se crean las instancias del programa, y es por este sistema visual de Interface Builder que nosotros le hemos pedido que las cree.

2. La ventana de la aplicación

Siguiendo con Interface Builder creamos la ventana del programa:Ventana del programaPara añadir la clase que hemos creado MVCVista, hace falta añadir una clase personalizada (custom class) a la ventana y con el inspector (menú Tools | Show Inspector, escoger la pestaña Custom Class) indicar que será la clase que hemos creado nosotros.Vemos que he añadido dos botones. Estos serán los que permitirán el dibujo de las rectas. Desde luego es un método muy tosco y realmente no estarán dentro de la clase MVCVista, pero en realidad la autentica Vista de la aplicación es la ventana, y tanto MVCVista cómo los botones son elementos de dentro de la vista.

3. ¡Conexiones!

Lo realmente importante viene aquí: cómo relacionamos los objetos que trabajarán en nuestro programa.Siguiendo el esquema lo primero es hacer que el controlador pueda acceder al modelo y a la vista. Para ello seleccionamos la clase MVCControl en la pestaña de instancias. Nos aseguramos de tener el inspector abierto en la pestaña de conexiones (connections) y añadimos dos salidas (outlets) de nombre dibujo y laRecta. Una vez creadas, las seleccionamos y las conectamos (Control y arrastrar) a la instancia de la clase que nos interesa.Conectando las SalidasLuego nos aseguramos que el controlador (MVCControl) pueda recibir los mensajes del usuario a través de la vista. Para ellos tenemos que crear dos acciones (actions) llamadas dibujarRecta: y dibujarOtra: en la misma pestaña que las salidas, pero en el apartado actions. En este caso la conexión la realizamos desde los botones a la instancia de la clase MVCControl.Creando las conexiones para las accionesCómo he dicho antes este método de utilizar dos acciones diferentes es un poco chapuza, pero para esta explicación nos valdrá.

4. Código

Todavía queda algo de trabajo en Interface Builder: crear los ficheros de las clases que hemos definido. Recordad que simplemente basta seleccionar la clase en la pestaña de clases y con el menú Classes | Create Files, crear los ficheros, asegurando que los incluimos en el proyecto.

4.1. Modelo

En el modelo el fichero de interficie es:

/* MVCRecta */
#import <Cocoa/Cocoa.h>
@interface MVCRecta : NSObject
{
    NSPoint inicio;
    NSPoint final;
}
-(void) init;
-(void) setInicio: (NSPoint)puntoInicio;
-(void) setFinal: (NSPoint)puntoFinal;
-(NSPoint) puntoInicial;
-(NSPoint) puntoFinal;
@end

Cada objeto de esta clase guardará dos datos inicio y fin de recta (siempre es bueno ser originales ;) ). Además habrá que escribir cinco métodos. Un iniciador y los correspondientes a establecer y mostrar los datos del objeto.Y el de implementación:

// Implentación de una clase que representa una linea recta
#import "MVCRecta.h"
@implementation MVCRecta
// Sobreescribimos la clase init para comenzar con
// una "recta" de un solo punto.
-(void) init
{
inicio = NSMakePoint(0,0);
    final = NSMakePoint(0,0);
    [super init];
}
// Métodos para establecer los puntos inicial y final
-(void) setInicio: (NSPoint)puntoInicio
{
    inicio = puntoInicio;
}
-(void) setFinal: (NSPoint)puntoFinal
{
    final = puntoFinal;
}
//Métodos para recuperar los datos de puntos inicial
// y final
-(NSPoint) puntoInicial{
    return inicio;
}
-(NSPoint) puntoFinal{
    return final;
}
@end

Nada especial, solamente ver cómo se sobrescribe el método init para asegurarnos que el objecto comienza con una “recta” no nula.

4.2. Controlador

En el controlador el fichero de interficie es:

/* MVCControl */
#import <Cocoa/Cocoa.h>
@interface MVCControl : NSObject
{
    IBOutlet id dibujo;
    IBOutlet id laRecta;
}

- (IBAction)dibujarOtra:(id)sender;
- (IBAction)dibujarRecta:(id)sender;@end

Aquí ya hay más cosas. En primer lugar las dos variables que nos marcarán donde estarán las salidas (IBOutlet) y por otro lado los dos métodos que tendremos que escribir en el control para interactuar con el programa (IBAction). No es difícil imaginar que las iniciales IB significan Interface Builder.Y el de implementación:

// Control para dibujar dos rectas en una vista
#import "MVCControl.h"
#import "MVCRecta.h"
#import "MVCVista.h"

@implementation MVCControl
// Método/Acción para dibujar una de las rectas
- (IBAction)dibujarOtra:(id)sender
{
    // Se indican los puntos inicial y final
    [laRecta setInicio:NSMakePoint(10,20)];
    [laRecta setFinal:NSMakePoint(50,200)];
    // Una vez definida la recta pide a la vista que
    // se actualice
    [dibujo setNeedsDisplay:YES];
}
// Método/Acción para dibujar una de las rectas
- (IBAction)dibujarRecta:(id)sender
{
    // Se indican los puntos inicial y final
    [laRecta setInicio:NSMakePoint(30,90)];
    [laRecta setFinal:NSMakePoint(150,300)];
    // Una vez definida la recta pide a la vista que
    // se actualice
    [dibujo setNeedsDisplay:YES];
}
@end

También es bastante sencillo, pero con unos detalles importantes.Cómo tiene que acceder a objetos de las clases MVCVista y MVCRecta hay que incluir la linea de #import correspondiente a cada clase.Hay que recordar las salidas que habíamos definido (laRecta y dibujo) a cada una de ellas se envían mensajes diferentes. A la primera los mensajes necesarios para definir la recta (en este caso totalmente fijada). Y a la segunda la necesidad de actualizar la vista. No tenemos que preocuparnos sobre cómo se dibujará la recta ni enviarla a la vista, la vista se encargará de todo (es que es muy lista).

4.3. Vista

En la modelo el fichero de interficie es:

/* MVCVista */
#import <Cocoa/Cocoa.h>

@interface MVCVista : NSView
{
    IBOutlet id laRecta2;
}
@end

Muy simple, sólo la salida al modelo.Y el código de implementación:

// Clase para representar una recta en una vista// personalizada
#import "MVCVista.h"
#import "MVCRecta.h"
@implementation MVCVista- (id)initWithFrame:(NSRect)frameRect
{
    if ((self = [super initWithFrame:frameRect]) != nil) {
        // Add initialization code here
     }
    return self;
}

- (void)drawRect:(NSRect)rect
{
    //Dibujar el fondo de color blanco
    [[NSColor whiteColor] set];
    [NSBezierPath fillRect:rect];

    // Recoger los puntos de la recta y dibujar en color negro
    NSPoint inicioRecta  = [laRecta2 puntoInicial];
    NSPoint finRecta = [laRecta2 puntoFinal];
    [[NSColor blackColor] set];
    [NSBezierPath strokeLineFromPoint:inicioRecta toPoint:finRecta];
}
@end

Támpoco nada de especial: los #import necesarios para tratar con la clase MVCRecta, la inicialización de la clase (que no se ha tocado para nada) y el método drawRect: para hacer el dibujo de la recta.Si vemos todo el código veremos muchas lineas para decir obviedades. Claro que es programa se podría haber solucionado con un sistema más sencillo y utilizar aquí el sistema Modelo Vista Controlador es un poco exagerado. Pero entonces la explicación no seria tan clara.

¡Hasta la próxima!

Anexos

Ficheros fuente: MVC.zip

Etiquetas: , ,

Una respuesta to “Modelo Vista Controlador”

  1. juan Says:

    holass…., el modelo que tu planteas no es del todo correcto, ya que, la vista no debe saber que existe el controlador!!…sino queda la tendalá nomapo!!…saludos!!

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


A %d blogueros les gusta esto: