Ejemplo de MVC (Modelo-vista-controlador)

Ejemplo de MVC (Modelo-vista-controlador)

Postby Compuin » Tue May 09, 2017 7:26 pm

Saludos

Existe algun ejemplo de como aplicar el MVC en Fivewin?
FWH 20.12
Hbmk2 32/64 Bits (Build 19.29.30133)
Microsoft Visual C 32 Bits
MySql 8.0.24 32/64 Bits
VS Code
Compuin
 
Posts: 1213
Joined: Tue Dec 28, 2010 1:29 pm
Location: Quebec, Canada

Re: Ejemplo de MVC (Modelo-vista-controlador)

Postby Carles » Wed May 10, 2017 9:33 am

Hola,

MVC te ayuda a estructurar el código de tu programa y a tenerlo mas "ordenado". Básicamente podrias tener esta estructura de directorios

Code: Select all  Expand view

+ codigo
     +--- controlador
     +--- modelo
     +--- vista
 


En la vista pondrias el diseño de de tus diálogos, ventanas,.... Por ejemplo imaginemos un dialog con 2 botones (Cargar, Salvar) --> VClientes.prg

En el controlador tendriamos un codigo que se dedica a escuchar las diferentes peticiones que nos hacen. En este caso imaginemos un sencillo case/encase --> CClientes.prg
Code: Select all  Expand view

function Control_Clientes( cOpcion )
   
   case 'Cargar' ; Cargar()
   case 'Salvar' ; Salvar()
   ...
 


En el modelo tendriamos nuestras conexiones a las bases de datos, tablas, rdds, ... y gestionaremos las peticiones. Imaginemos que en la function Cargar() del Control_Clientes llamamos a un modelo de datos llamado cliente. Este modelo puede ser una sencialla clase con la definicion de campos, como se conecta (mysql,dbf,..) y metodos que tendra como por ejemplo Load()/Save() --> MClientes.prg. En este caso desde el controlador creariamos una instancia a la clase cliente (modelo) y ejecutariamos el metodo Load().

Este codigo estaria en la parte del controlador

Code: Select all  Expand view

Function Cargar()

   oCliente := TCliente():New()

return oCliente->Load()
 


Solo te faltaria definir el modelo de clientes pero el concepto ya esta explicado.

Asi pues te quedaria en este caso una estructura asi:

Code: Select all  Expand view

+ codigo
     +--- controlador
           +--- cclientes.prg
     +--- modelo
           +--- mclientes.prg
     +--- vista
           +--- vclientes.prg
 


Ahora solo quedaria ajustar un buen make y listos. Parece muy costoso y muchos piensan que en un solo prg lo podemos todo y es cierto pero cuando haces grandes proyectos, has de saber estructurar muy bien el codigo para crear un buen programa. Despues las ventajas que tienes cuando has asimilado esta técnica son muchas: sabes donde poner cada parte del código, si hay fallo sabes donde ir perfectamente, si cambias de base de datos, rdd, ... solo con ir al modelo lo podrias solucionar, ...

Esta es una explicación lo mas básica que he podido hacer, pero tienes ya una base para poder trabajar. Te aconsejo para grandes proyectos empezar a asimilar esta manera de trabajar y ya veras como te beneficias un monton. El sistema lo puedes complicar tanto como quieras y siempre hay los detractores y los defensores, pero.... :roll:

Espero que te ayude la explicacion. :D
Salutacions, saludos, regards

"...programar es fácil, hacer programas es difícil..."

UT Page -> https://carles9000.github.io/
Forum UT -> https://discord.gg/bq8a9yGMWh
Skype -> https://join.skype.com/cnzQg3Kr1dnk
User avatar
Carles
 
Posts: 1090
Joined: Fri Feb 10, 2006 2:34 pm
Location: Barcelona

Re: Ejemplo de MVC (Modelo-vista-controlador)

Postby xmanuel » Wed May 10, 2017 1:54 pm

La arquitectura de programación es un tema que me apasiona.
Se trata de separar la vista de los datos y los procesos.
Como dice Carles la vista podrían ser los diálogos, ventanas... o informes, no tiene porqué ser sólo la parte visual aunque con eso se puede explicar más facilmente.
Hace tiempo hice un ejemplo orientado al objeto que demuestra lo bueno y fácil que es hacer uso de la arquitectura de programación ya que está basado en la experiencia de muchos programadores.
El ejemplo no está hecho en FWH pero como dije antes con sólo cambiar la vista (vistaTXT.prg y crear un vistaGUI.prg debe de funcionar).
Aquí esta el programa que pone en marcha el sistema MVC:

Code: Select all  Expand view

/*
 * Proyecto: PruebaMVC
 * Fichero: P00.prg
 * Descripción: Ejemplo modo texto de las clases.
 * Autor: Manu Exposito Suárez
 * Fecha: 20/09/2011
 * Version: 0.12
 */


//-----------------------------------------------------------------------------

#include "hbclass.ch"

//-----------------------------------------------------------------------------

REQUEST HB_GT_WIN

//-----------------------------------------------------------------------------
// Programa principal de la prueba

FUNCTION main()

    LOCAL oPrg := Programa():new()

    cls

    @ 01, 10 SAY "Ejemplo del patron Modelo Vista Controlador"

    oPrg:ejecuta()

RETURN nil

//-----------------------------------------------------------------------------
// Clase principal para el ejemplo de pruebas etc

CLASS Programa

    DATA control

    METHOD new() CONSTRUCTOR
    METHOD ejecuta()

ENDCLASS

//-----------------------------------------------------------------------------

METHOD new() CLASS Programa

    ::control := ControlConversor():new( VistaTXT():new(), ;
       ConversorEurosPesetas():new() )

RETURN self

//-----------------------------------------------------------------------------

METHOD ejecuta() CLASS Programa

    ::control:getVista():arranca()

RETURN nil

//-----------------------------------------------------------------------------
 


Esta es la Vista, que como esta orientada al objeto, creo una clase abstracta desde la que se heredarán las vistas concretas:

Code: Select all  Expand view

//---------------------------------------------------------------------------//
//  AUTOR.....: Manuel Expósito Suárez   Soft4U 2002-2011                    //
//  CLASE.....: MVC - Vista - InterfazVista                                  //
//  FECHA MOD.: 20/11/2011                                                   //
//  VERSION...: 1.00                                                         //
//  PROPOSITO.: Ejemplo de Modelo Vista Controlador                          //
//---------------------------------------------------------------------------//

#include "HbClass.ch"

//-----------------------------------------------------------------------------
// Vista 1/2
// Clase para Abstracta para la creacion de vistas.
// En las clases derivadas hay que implementar al menos estos 4 metodos

CREATE CLASS InterfazVista

    PROTECTED:
    DATA controlador
    DATA tipoConversion // "Pesetas a Euros" -> 0  "Euros a Pesetas" -> 1

    EXPORTED:
    // Se implementan en cada vista
    METHOD arranca()    VIRTUAL
    METHOD getCantidad()   VIRTUAL
    METHOD escribeCambio( s )  VIRTUAL

    // SET GET
    METHOD setControlador( oControlador )
    METHOD getControlador()
    METHOD setTipoConversion( nTipo )
    METHOD getTipoConversion()

ENDCLASS

//-----------------------------------------------------------------------------
// Asigna el tipo Conversion

METHOD setTipoConversion( nTipo ) CLASS InterfazVista

    LOCAL ret := ::tipoConversion

    IF ValType( nTipo ) == "N" .and. ( nTipo == 0 .or. nTipo == 1 )
        ::tipoConversion := nTipo
    END IF

RETURN ret

//-----------------------------------------------------------------------------
// Obtiene el tipo Conversion

METHOD getTipoConversion() CLASS InterfazVista
RETURN ::tipoConversion

//-----------------------------------------------------------------------------
// Asigna el controlador

METHOD setControlador( oControlador ) CLASS InterfazVista

    LOCAL ret := ::controlador

    IF ValType( oControlador ) == "O"
        ::controlador := oControlador
    END IF

RETURN ret

//-----------------------------------------------------------------------------
// Obtiene el tipo controlador

METHOD getControlador() CLASS InterfazVista
RETURN ::controlador

//-----------------------------------------------------------------------------
 


Esta es la vista "concreta"en modo texto:
Code: Select all  Expand view

//---------------------------------------------------------------------------//
//  AUTOR.....: Manuel Expósito Suárez   Soft4U 2002-2011                    //
//  CLASE.....: MVC - Vista - VistaTXT                                       //
//  FECHA MOD.: 20/11/2011                                                   //
//  VERSION...: 1.00                                                         //
//  PROPOSITO.: Ejemplo de Modelo Vista Controlador                          //
//---------------------------------------------------------------------------//

#include "HbClass.ch"

//-----------------------------------------------------------------------------
// Vista 2/2

CREATE CLASS VistaTXT FROM InterfazVista

    PROTECTED:
    METHOD leeOpcion()
    METHOD leeCantidad()
    METHOD solicitaOperacion()
    METHOD procesaNuevaOperacion()
    METHOD operacionIncorrecta()

    EXPORTED:
    METHOD new() CONSTRUCTOR
    // Implementacion de los metodos de la interfaz vista
    METHOD arranca()
    METHOD escribeCambio()
    METHOD getCantidad()

ENDCLASS

//-----------------------------------------------------------------------------
// Constructor

METHOD new( oControlador ) CLASS VistaTXT

    IF ValType( oControlador ) == "O"
        ::controlador := oControlador
    END IF

RETURN Self

//-----------------------------------------------------------------------------
// Pone en marcha la vista

METHOD arranca() CLASS VistaTXT

    ::procesaNuevaOperacion()

RETURN nil

//-----------------------------------------------------------------------------
// Se encarga de sacar por pantalla la informacion

METHOD escribeCambio( s ) CLASS VistaTXT

    CLS

    ?
    ?
    ? "Resultado --->", s
    ?
    ?
    ::procesaNuevaOperacion()

RETURN nil

//-----------------------------------------------------------------------------
// Obtiene la cantidad

METHOD getCantidad() CLASS VistaTXT
RETURN ::leeCantidad()

//-----------------------------------------------------------------------------

METHOD leeOpcion() CLASS VistaTXT

    LOCAL cOpcion := " "
    LOCAL getList := {}

    @ row() + 1, col() SAY "Elige opcion:"  GET cOpcion

    READ

    cOpcion  := AllTrim( cOpcion )

    IF !( cOpcion $ " 0 1 2 " )
        ::operacionIncorrecta()
    END IF

RETURN cOpcion

//-----------------------------------------------------------------------------

METHOD leeCantidad() CLASS VistaTXT

    LOCAL nCantidad := 0
    LOCAL getList := {}

    @ row(), col() SAY "Cantidad:" GET nCantidad

    READ

RETURN nCantidad

//-----------------------------------------------------------------------------

METHOD solicitaOperacion() CLASS VistaTXT

    ? "----------------------------------------------------------------------"
    ? "Indical operacion que quieres realizar:"
    ? "---------------------------------------"
    ?
    ? "1 Pesetas a euros"
    ? "2 Euros a pesetas"
    ? "0 Salir"
    ?
    ?

RETURN nil

//-----------------------------------------------------------------------------

METHOD procesaNuevaOperacion() CLASS VistaTXT

    ::solicitaOperacion()

    SWITCH ::leeOpcion()
    CASE '0'
        ?
        ? "Adios"
        ?
        quit
    CASE '1'
        ::setTipoConversion( 0 )
        ::controlador:gestionDeAcciones()
        EXIT
    CASE '2'
        ::setTipoConversion( 1 )
        ::controlador:gestionDeAcciones()
        EXIT
        //DEFAULT
    OTHERWISE
        ::operacionIncorrecta()
    END SWITCH

RETURN nil

//-----------------------------------------------------------------------------

METHOD operacionIncorrecta() CLASS VistaTXT

    ?
    ? "Valor incorrecto..."
    ?
    InKey( 5 )
    cls
    ::procesaNuevaOperacion()

RETURN nil

//-----------------------------------------------------------------------------
 


Ahora es el turno de los modelos:
Code: Select all  Expand view

//---------------------------------------------------------------------------//
//  AUTOR.....: Manuel Expósito Suárez   Soft4U 2002-2011                    //
//  CLASE.....: MVC - Modelo - ConversorEuros                                //
//  FECHA MOD.: 20/11/2011                                                   //
//  VERSION...: 1.00                                                         //
//  PROPOSITO.: Ejemplo de Modelo Vista Controlador                          //
//---------------------------------------------------------------------------//

#include "HbClass.ch"

//-----------------------------------------------------------------------------
// Modelo 1/2
// Clase para convertis cualquier moneda a Euros

CREATE CLASS ConversorEuros

    PROTECTED:
    DATA cambio

    EXPORTED:
    METHOD new( valorCambio ) CONSTRUCTOR
    METHOD eurosAMoneda( cantidad )
    METHOD monedaAEuros( cantidad )
    // SET GET
    METHOD setCambio( cambio )
    METHOD getCambio()

ENDCLASS

//-----------------------------------------------------------------------------
// Constructor

METHOD new( valorCambio ) CLASS ConversorEuros

    IF ValType( valorCambio ) == "N"
        ::cambio := valorCambio
    ENDIF

RETURN Self

//-----------------------------------------------------------------------------
// Pasa euros a la moneda

METHOD eurosAMoneda( cantidad ) CLASS ConversorEuros
RETURN IF( ValType( cantidad ) == "N", cantidad * ::cambio, 0 )

//-----------------------------------------------------------------------------
// Pasa las monedas a euros

METHOD monedaAEuros( cantidad ) CLASS ConversorEuros
RETURN IF( ValType( cantidad ) == "N", cantidad / ::cambio, 0 )

//-----------------------------------------------------------------------------
// Asigna el cambio

METHOD setCambio( cambio ) CLASS ConversorEuros

    LOCAL ret := ::cambio

    IF ValType( cambio ) == "N"
        ::cambio := cambio
    END IF

RETURN ret

//-----------------------------------------------------------------------------
// Obtiene el cambio

METHOD getCambio() CLASS ConversorEuros
RETURN ::cambio

//-----------------------------------------------------------------------------
 


Y ahora el otro modelo que es otro el otro conversor:

Code: Select all  Expand view

//---------------------------------------------------------------------------//
//  AUTOR.....: Manuel Expósito Suárez   Soft4U 2002-2011                    //
//  CLASE.....: MVC - Modelo - ConversorEurosPesetas                         //
//  FECHA MOD.: 20/11/2011                                                   //
//  VERSION...: 1.00                                                         //
//  PROPOSITO.: Ejemplo de Modelo Vista Controlador                          //
//---------------------------------------------------------------------------//

#include "HbClass.ch"

//-----------------------------------------------------------------------------
// Modelo 2/2
// Clase para convertir pesetas a Euros

CREATE CLASS ConversorEurosPesetas FROM ConversorEuros

    METHOD new() CONSTRUCTOR

ENDCLASS

//-----------------------------------------------------------------------------
// Constructor

METHOD new() CLASS ConversorEurosPesetas

    ::setCambio( 166.386 )

RETURN Self

//-----------------------------------------------------------------------------

 


Y por último en corazón, o sea el controlador, en este caso un controlador frontal:

Code: Select all  Expand view

//---------------------------------------------------------------------------//
//  AUTOR.....: Manuel Expósito Suárez   Soft4U 2002-2011                    //
//  CLASE.....: MVC - Controlador - ControlConversor                         //
//  FECHA MOD.: 20/11/2011                                                   //
//  VERSION...: 1.00                                                         //
//  PROPOSITO.: Ejemplo de Modelo Vista Controlador                          //
//---------------------------------------------------------------------------//
/*
 El CONTROLADOR
 Desde aqui se reciben las peticiones del usuario a travez de la VISTA y se
 trasladan al MODELO
*/


#include "HbClass.ch"

//-----------------------------------------------------------------------------
// Control 1/1

CREATE CLASS ControlConversor

    PROTECTED:
    DATA vista
    DATA modelo

    EXPORTED:
    METHOD new( vista, modelo ) CONSTRUCTOR
    METHOD gestionDeAcciones( cTipo )

    METHOD getVista()
    METHOD setVista( vista )
    METHOD getModelo()
    METHOD setModelo( modelo )

ENDCLASS

//-----------------------------------------------------------------------------
// Constructor

METHOD new( vista, modelo ) CLASS ControlConversor

    ::vista := vista
    ::modelo := modelo

    ::vista:setControlador( Self )

RETURN self

//-----------------------------------------------------------------------------
// Control de acciones

METHOD gestionDeAcciones() CLASS ControlConversor

    LOCAL cantidad := ::vista:getCantidad()

    IF ::vista:getTipoConversion() == 0
        ::vista:escribeCambio( AllTrim( str( cantidad ) ) + " pesetas son: " + ;
           AllTrim( str( ::modelo:monedaAEuros( cantidad ) ) ) + " euros" )
    ELSEIF ::vista:getTipoConversion() == 1
        ::vista:escribeCambio( AllTrim( str( cantidad ) ) + " euros son: " + ;
           AllTrim( str( ::modelo:eurosAMoneda( cantidad ) ) ) + " pesetas" )
    ELSE
        ::vista:escribeCambio( "ERROR" )
    END IF

RETURN nil

//-----------------------------------------------------------------------------
// Obtiene la vista

METHOD getVista() CLASS ControlConversor
RETURN ::vista

//-----------------------------------------------------------------------------
// Asigna la vista

METHOD setVista( vista ) CLASS ControlConversor

    ::vista := vista

RETURN nil

//-----------------------------------------------------------------------------
// Obtiene el modelo

METHOD getModelo() CLASS ControlConversor
RETURN ::modelo

//-----------------------------------------------------------------------------
// Asigna el modelo

METHOD setModelo( modelo ) CLASS ControlConversor

    ::modelo := modelo

RETURN nil

//-----------------------------------------------------------------------------
 


Y eso es todo, cuando se le coge el truco es el mejor sistema, créanme.
______________________________________________________________________________
Sevilla - Andalucía
xmanuel
 
Posts: 756
Joined: Sun Jun 15, 2008 7:47 pm
Location: Sevilla

Re: Ejemplo de MVC (Modelo-vista-controlador)

Postby Carlos Mora » Thu May 11, 2017 12:12 pm

Manu,
interesante ejemplo, sobre el cual me permito hacer alguna observación:

Tu controlador tiene cosas como AllTrim( str( cantidad ) ) + " pesetas son: " + AllTrim( str( ::modelo:monedaAEuros( cantidad ) ) ) + " euros" , que es parte de la VISTA. Se demuestra si tratamos de traducir la app a otro idioma, tendríamos que cambiar el controlador, lo que se supone que si está bien no debería suceder.

El patrón MVC define Modelo, Vista y Controlador, pero si queremos un framework completo, la arquitectura necesita de más aditamentos: un router que mueve los mensajes, una petición (o request) una respuesta ( o response), y más cacharros que 'aceitan' los engranajes. Es una forma no muy lineal que cuesta alinearla con el modelo mental que automaticamente usamos cundo programamos en Harbour clásico.
Tu vista tiene un método GetCantidad, GetTipoConversion que estarían en la request. En realidad existirían 2 clases de request: la RequestEuroToPesetas y otra RequestPesetaAEuro, la vista genera los eventos de forma apropiada creando una u otra request. El controlador la recibe y en un case le pasará el mensaje apropiado al Modelo, que hará la conversión, creará una nueva response que se enviará a la vista correspondiente.

Es característico que los controladores tiende a ser muy pequeños, de muy poquitas líneas, porque solo dirigen el tráfico, no alteran ni solicitud ni respuesta, solo invocan modelos y vistas. Lo gordo suele estar del lado del modelo, donde se encuentan frecuentemente, para cada objeto, una clase Repositorio y una clase Entidad. En la clase repositorio estarían los métodos que afectan al conjunto de entidades: por ejemplo en el repositorio FacturasRepo habría un método TodasDeCliente( cCodCliente ) que devolvería una colección de objetos EntidadFactura, aquellas que corresponden a un determinado cliente. En cambio la clase EntidadFactura tendría métodos tipo EstaVencida() ( boolean ) o TotalFactura() que afectan a un solo individuo o entidad.

Retomando el concepto de 'router', 'request' y 'response', estas clases son particulares de el entorno de la aplicacion: no es lo mismo un ruter de una app de escritorio, de una app web (como Fiveweb o FWeb).

Bueno, tengo que volver al curro, pero... pufff da para muchísimo.

El Rafa subió en algun momento un ejemplo de una aplicacion web escrita en Harbour usando el http server de Harbour. Si adaptas tu código para que responda usando la estructura de esa aplicacion el panorama se aclara muchísimo.

Un saludo
Saludos
Carlos Mora
http://harbouradvisor.blogspot.com/
StackOverflow http://stackoverflow.com/users/549761/carlos-mora
“If you think education is expensive, try ignorance"
Carlos Mora
 
Posts: 988
Joined: Thu Nov 24, 2005 3:01 pm
Location: Madrid, España

Re: Ejemplo de MVC (Modelo-vista-controlador)

Postby xmanuel » Thu May 11, 2017 12:57 pm

:D Cuánta razón tienes Carlos!!!

Esto era una aproximación, lo importante era crear el debate a partir de la entrada de Compuin. Básicamente porque me interesa muchísimo.
EL MVC se aplica perfectamente en aplicaciones web ya que el concepto de enrutador y request y response (con GET o POST) están muy bien definidos.

La propuesta que hago es que a partir de lo que hay se implemente lo que falta o se mejore lo ya expuesto... quien se anima? :roll: 8) :lol:
______________________________________________________________________________
Sevilla - Andalucía
xmanuel
 
Posts: 756
Joined: Sun Jun 15, 2008 7:47 pm
Location: Sevilla

Re: Ejemplo de MVC (Modelo-vista-controlador)

Postby Compuin » Thu May 11, 2017 1:03 pm

Excelente debate!

Cada punto de vista aporta conocimiento y entre todos aprendemos
FWH 20.12
Hbmk2 32/64 Bits (Build 19.29.30133)
Microsoft Visual C 32 Bits
MySql 8.0.24 32/64 Bits
VS Code
Compuin
 
Posts: 1213
Joined: Tue Dec 28, 2010 1:29 pm
Location: Quebec, Canada


Return to FiveWin para Harbour/xHarbour

Who is online

Users browsing this forum: Google [Bot] and 87 guests