Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > OOP
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 16-03-2008
harpo harpo is offline
Miembro
 
Registrado: jul 2006
Posts: 35
Poder: 0
harpo Va por buen camino
Thumbs up Patrón

Buenas gente,

a ver si me podeis echar una manita con el rediseño de un programa.

Tengo un form principal, una serie de frames y una máquina de estados para controlar la visualización de los frames, entre otras cosas. Hasta ahora el diseño era un poco chapuza, el form principal contiene las referencias a todos los frames y la creación de los estados de la máquina. A parte, cada frame contiene referencias a otros frames "hermanos" que necesita y referencias al frame principal, con lo cual tengo un lío tremendo de referencias circulares.

Algunas partes del código

Form principal
Código:
TfrMain = class(TForm)
    frToolbar: TfrToolbar;
    procedure mmExitClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    frNavBarLeft    :TfrNavBarLeft;
    frNavBarRight   :TfrNavBarRight;
    frEditPatient   :TfrEditPatient;
    frViewPatient   :TfrViewPatient;
    frBlank         :TfrBlank;
    frViewImage     :TfrViewImage;
    frViewStudy     :TfrVIewStudy;
    frViewImageTwin :TfrViewImageTwin;
    frCamera        :TfrCamera;
    frEditStudy     :TfrEditStudy;
    frPrint         :TfrPrint;
    frProcesses     :TfrProcesses;
  end;


var
  frMain: TfrMain;

implementation

{$R *.dfm}

procedure TfrMain.mmExitClick(Sender: TObject);
begin
  frMain.Close;
end;

procedure TfrMain.FormCreate(Sender: TObject);
begin


  frBlank         :=TfrBlank.Create(Self);
  frNavBarLeft    :=TfrNavBarLeft.Create(Self);
  frViewPatient   :=TfrViewPatient.Create(self);
  frEditPatient   :=TfrEditPatient.Create(Self);
  frViewImage     :=TfrViewImage.Create(Self);
  frViewStudy     :=TfrViewStudy.Create(Self);
  frViewImageTwin :=TfrViewImageTwin.Create(Self);
  frCamera        :=TfrCamera.Create(Self);
  frEditStudy     :=TfrEditStudy.Create(Self);
  frPrint         :=TfrPrint.Create(Self);
  frProcesses     :=TfrProcesses.Create(Self);

  frBlank.Parent          :=Self;
  frNavBarLeft.Parent     :=Self;
  frViewPatient.Parent    :=Self;
  frEditPatient.Parent    :=Self;
  frViewImage.Parent      :=Self;
  frViewStudy.Parent      :=Self;
  frViewImageTwin.Parent  :=Self;
  frCamera.Parent         :=Self;
  frEditStudy.Parent      :=Self;
  frPrint.Parent          :=Self;
  frProcesses.Parent      :=Self;

  sessiondate:=now;
  states:=TStateMachine.Create;

  frNavBarLeft.ReLoadTreeView;
  frMain.TabStop:=false;

  states.Add (
                stBlank,
                frBlank.frEnter,
                frBlank.frExit,
                frBlank,
                true,
                frToolBar.menu
              );

  states.Add (
                stViewPatient,
                frViewPatient.frEnter,
                frViewPatient.frExit,
                frViewPatient,
                true,
                frToolBar.menu
              );

 // y bla bla bla... demás estados ....

  states.Enter(stBlank);
end;
Máquina Estados (parte de interés)
Código:
  TProc = procedure of object;
  {
    TState:
    state type for the State Machine
  }
  TState = record
    id:integer;  //id state (for ex. stBlank, stViewPatient)
    inProc:TProc;    //initial process
    outProc:TProc;    //fianl process
    frame:TFrame; //frame corresponding for this state
    navBarL:Boolean; //bars must be shown
    menu:TMainMenu; //main menu for this frame (use to be main menu of the
                    //toolbar frame
  end;

  {
    TStateMachine:
    Controls the state of the program and manage the interface active frame
  }
  TStateMachine = class
  private
    states:array of TState;    //posible states           
    procedure stExit(id:integer);
  public
    current:integer; // current state
    last:integer;    //last state (for goback function)
    OnRecordChange:TNotifyEvent;
    stack:TStack;
     procedure Add(id:integer;ip,op:TProc;frame:TFrame;nbl:boolean;menu:TMainMenu);     procedure SetInProc(proc:TProc;state:integer);
    procedure Enter(id:integer);

    constructor Create;
    destructor Destroy; override;

var
  states      :TStateMachine;
  sessionDate :TDateTime;

implementation


procedure TStateMachine.Add(id:integer;ip,op:TProc;frame:TFrame;
                            nbl:boolean;menu:TMainMenu);
var
  l :integer;
begin
  l := Length(states);
  SetLength(states,l+1);
  states[l].id := id;
  states[l].inProc := ip;
  states[l].outProc := op;
  states[l].frame := frame;
  states[l].menu := menu;
  states[l].navBarL := nbl;
end;

procedure TStateMachine.Enter(id: integer);
var
  i,j:integer;
begin
  for i := 0 to length(states)-1 do
    if id = states[i].id then
    begin
      stExit(current);
      current := id;
      frMain.frNavBarLeft.Visible := states[i].navBarL;
      frMain.Menu := states[i].menu;
      with states[i].frame do
      begin
        Align := alClient;
        Visible := True;
      end;
      states[i].inProc;
    end;

end;

procedure TStateMachine.stExit(id:integer);
var
  i :integer;
begin
  for i := 0 to length(states)-1 do
  if id=states[i].id then
  begin
    last := current;
    current := -1;
    states[i].outProc;
    states[i].frame.Align := alNone;
    states[i].frame.Visible := False;
  end;
end;
Pues bien, ahora la idea es hacer un diseño más correcto, algo de este tipo:



Y un pequeño resumen, de cómo considero que son/deberían ser las cosas, pero que no consigo ver claro cómo hacer:
  • Un frame representa un "estado" del programa claramente definido.
  • Las acciones del usuario cambian el estado del programa, por lo tanto debe haber un sistema para cambiar entre los estados correspondientes.
  • Cada frame debe ser independiente y no debe incluir units de otros frames "hermanos".
  • Los frames NO deben referenciar al formulario principal directamente, ni otros miembros del mismo.
  • Para los elementos de la pantalla que si o si deben compartirse entre frames, como los botones, o que deben ser persistentes, como los thumbnails, debe haber un sistema que publique globalmente los diferentes bloques (botonera, thumbnails), para que cada frame pueda obtener y manejar los bloques que necesita y conozca, mientras el resto de los bloques permanece desactivado.
  • Debe haber un sistema para transferir datos entre los distintos frames durante un cambio de estado, ya sean imagenes, claves de la DB, u otros parametros.
  • El uso y la asociacion de los frames a los estados, debe ser lo mas transparente posible ( o sea, no tener que agregar el frame en 50 lugares diferentes)
  • Cada frame o estado deberia tener un procedimiento de entrada y de salida, en el que recibe el estado desde o hacia el cual se transfiere, junto con parametros opcionales. Este procedimiento debe ser privado, y no utilizado afuera del frame en cuestion.
  • Los parametros utilizados para la transferencia de datos deben estar especificados en una estructura estandar, como podria ser una lista de nombres y valores.
Ahora las preguntas...
¿Qué patrones de diseño veis aquí?
¿Singleton para la máquina de estados?
¿Alguna manera de evitar el rollo de las referencias circulares... sin hacer el chapuceo de los uses en la implementación?

(Perdón por el rollo :P )
Responder Con Cita
  #2  
Antiguo 16-03-2008
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: jul 2004
Ubicación: Salta, Argentina
Posts: 5.582
Poder: 25
Delphius Va camino a la fama
Cita:
Empezado por harpo Ver Mensaje
Buenas gente,

a ver si me podeis echar una manita con el rediseño de un programa.

Tengo un form principal, una serie de frames y una máquina de estados para controlar la visualización de los frames, entre otras cosas. Hasta ahora el diseño era un poco chapuza, el form principal contiene las referencias a todos los frames y la creación de los estados de la máquina. A parte, cada frame contiene referencias a otros frames "hermanos" que necesita y referencias al frame principal, con lo cual tengo un lío tremendo de referencias circulares.

Pues bien, ahora la idea es hacer un diseño más correcto, algo de este tipo:



Y un pequeño resumen, de cómo considero que son/deberían ser las cosas, pero que no consigo ver claro cómo hacer:
  • Un frame representa un "estado" del programa claramente definido.
  • Las acciones del usuario cambian el estado del programa, por lo tanto debe haber un sistema para cambiar entre los estados correspondientes.
  • Cada frame debe ser independiente y no debe incluir units de otros frames "hermanos".
  • Los frames NO deben referenciar al formulario principal directamente, ni otros miembros del mismo.
  • Para los elementos de la pantalla que si o si deben compartirse entre frames, como los botones, o que deben ser persistentes, como los thumbnails, debe haber un sistema que publique globalmente los diferentes bloques (botonera, thumbnails), para que cada frame pueda obtener y manejar los bloques que necesita y conozca, mientras el resto de los bloques permanece desactivado.
  • Debe haber un sistema para transferir datos entre los distintos frames durante un cambio de estado, ya sean imagenes, claves de la DB, u otros parametros.
  • El uso y la asociacion de los frames a los estados, debe ser lo mas transparente posible ( o sea, no tener que agregar el frame en 50 lugares diferentes)
  • Cada frame o estado deberia tener un procedimiento de entrada y de salida, en el que recibe el estado desde o hacia el cual se transfiere, junto con parametros opcionales. Este procedimiento debe ser privado, y no utilizado afuera del frame en cuestion.
  • Los parametros utilizados para la transferencia de datos deben estar especificados en una estructura estandar, como podria ser una lista de nombres y valores.
Ahora las preguntas...
¿Qué patrones de diseño veis aquí?
¿Singleton para la máquina de estados?
¿Alguna manera de evitar el rollo de las referencias circulares... sin hacer el chapuceo de los uses en la implementación?

(Perdón por el rollo :P )
Bueno, una lecturá rápida me dio una interpretación de esto:

1. Existe una única manquina de estados, por lo que estamos hablando de un singleton.
2. Cada estado es en cierta medida independiente pero las acciones del usuario conducen a que se provoquen ciertos cambios y en la elección de los estados. Eso es lo que entiendo. A simple vista pareciera que estamos en una combinación de estrategia (Strategy) y Composite.

3. Los frames son indenpendientes pero son el reflejo de los estados. Um.... pareciera ser algo como el Patrón Observador/Observado pues, si los frames representan "visualmente" a los estados y estos dependerán de un curso de acción... y si se desea una cierta independencia entre la lógica de estados y los frames lo más "simple" es tener un modelo de Observador (Observer).

Bueno... eso fue un primer análisis de lo que voy entiendo acerca de lo que deseas hacer. Muy posiblemente esté equivocado pero al menos ya tienes un punto de vista.

Por otro lado recuerda que no existe una única alternativa, esto de los patrones, UML y POO es bastante subjetivo y pueden existir tantos diseños como personas en el mundo.

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Patron GoF: Factoría ¿Como y cuando se usa? Delphius OOP 2 26-12-2007 06:37:32
En access hay botón buscador-en form permite buscar patron-existe uno en Delphi igual Ale Alvarez OOP 9 26-09-2007 07:13:44
Patrón observador, attach, notify,update ... adpa OOP 5 22-01-2006 01:07:40
Patrón de los Informáticos. obiwuan Varios 20 10-09-2003 14:44:54


La franja horaria es GMT +2. Ahora son las 17:12:13.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi