Ir al contenido


Foto

problema de decision de diseño con patrones y poo


  • Por favor identifícate para responder
6 respuestas en este tema

#1 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 05 mayo 2016 - 12:30

Bueno como me aconsejo el amigo Delphius, quiero mostrarles el diseño de mi aplicacion y que me aconsejen..

 

Situacion: es un sistema de facturacion electronica para argentina. el primer web service que debe ser invocado es el de autorizacion y autenticacion (WSAA).

 

1- el mismo devuelve un sign y token. al invocarlo se especifica el servicio para el cual se pide el ticket de acceso, es decir la autorizacion: busqueda en el padron(wspn10), factura elecronica(wsfev1) de exportacion(wsfex). 

2- el mismo puede ser reutilizado..de hecho el server de la afip devuelve un error en caso de solicitar autorizacion para un servicio que no ha expirado.

 

entonces yo pense colocar una unidad con una clase login (nombre que se me ocurrio, no definitivo).

para lo mismo use la clase thttprio en tiempo de ejecucion(osea no arrastre un componente) y la interfaz ixmldocument..para cargar y leer nodos xml. y el xml data binding.

IMPORTANTE: me habia olvidado de postear el codigo openssl que se debe ejecutar:


delphi
  1. ShellExecute(0,'open',PWideChar(rutabat),nil, nil,0); 

y en rutabat: c:\OpenSSL-Win32\bin\openssl.exe smime -sign -signer C:\OpenSSL-Win32\bin\certificado.crt -inkey C:\OpenSSL-Win32\bin\caruso12021991.key -out D:\TPV\Win32\Debug\LoginTicketRequest.xml.cms -in D:\TPV\Win32\Debug\LoginTicketRequest.xml -outform PEM -nodetach

Atributos:

-servicio:nombre del servicio al que se desea acceder. string

-token y sign: 2 string que se setean luego de ejecutar el proceso de obtencion de los mismos(llamo al ws y evaluo el xml resultante)

-expiration: es la hora a la que expira.

 

implementacion:

 

crear un objeto login y pasarle al constructor el servicio como parametro.


delphi
  1. login:=TLogin.Loguearse('wsfe');
  2. xml1:=NewXMLDocument;
  3. xml1:=login.guardarXML();
  4. xml2:=NewXMLDocument;
  5. cms:=login.generarCMS(xml1);
  6. xml2:=login.respuestaXML(cms);
  7.  
  8. sign:=login.obtenersign(xml2);
  9. ShowMessage(sign);

PROBLEMA:

 

1- como diseñar el acceso a cualquier servicio.Tener en cuenta que lo unico que cambia es el nombre del servicio que se coloca en el xml que es enviado a la AFIP..osea es un solo atributo string..el proceso es el mismo.

2-reutilizar la autorizacion generada cuando se trate de un mismo servicio siempre que la hora actual sea anterior a la hora de expiracion  del ultimo certificado generado.

 

POSIBLE SOLUCION PROPIA:

 

utilizar el paron factory methos para crear el tipo de login(para lo mismo crear clases que hereden: loginwsfe,loginwsfex).

 

utilizar el patron singleton..para que, mientras se corre la aplicacion exista una y solo una instancia de cada clase concreta de login.. Para lo mismo login y sus clases hijas tendrian un metodo renovar.. que lo solicita de vuelta. cuando se cierra la aplicacion se destruyen todos los objetos.

 

Muchas gracias..

 


  • 0

#2 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 05 mayo 2016 - 04:03

Siempre aconsejo evitar el "patron" singleton

 

Es un diseño que esta roto desde el vamos (variable global, viola SOLID, acarrea estado, dificil de testear, inutil en multi-threading)

 

Si necesitas una sola instancia de cierta clase, creas una y listo :)


  • 0

#3 Delphius

Delphius

    Advanced Member

  • Moderadores
  • PipPipPip
  • 6.295 mensajes
  • LocationArgentina

Escrito 05 mayo 2016 - 06:17

Si no hay demasiadas clases hijas yo directamente no dispondría de esa  fábrica. Directamente pondría un Adaptador a modo de Fachada que tenga como atributos uno de cada clase hija y haría uso de materialización peresoza. De este modo las clases clientes solamente interactúa con este Adaptador/Fachada. Este adaptador delega el trabajo sucio a la clase hija en cuestión.

 

Vendría a ser algo como esto:


delphi
  1. TAFIPServicesAdapter = class
  2. private
  3. FService1AFIP: TService1AFIP;
  4. FService2AFIP: Tservice2AFIP;
  5. ...
  6. FServiceNAFIP: TServiceNAFIP;
  7. public
  8. // aquí los métodos públicos que se consideren necesarios para interactuar
  9. // con los servicios adecuados
  10. end;

¿Que implica esta materialización peresoza? Básicamente la creación de una clase por demanda y sólo cuando efectivamente se lo requiere. Para no malgastar en tener objetos y más memoria ociosa.

Nota que al ser atributos internos el cliente ni se entera de quien está haciendo el trabajo. Para el cliente le resulta insignificante... ni se entera que hay detrás del Adapter.

 

El Adapter delegará y asumirá la tarea de crear cada Service (me parece el nombre más adecuado  ;)  ) y mantendrá esa única referencia para siempre. Ahí te ahorras el hacer el Singletón... ¡Ya lo tienes con esa variable! ;)

 

El trabajo podría ser algo como:


delphi
  1. procedure TAFIPServicesAdapter.GenerateElectronicBill(// algunos parámetros);
  2. begin
  3. // supongamos que el encargado de hacer la factura electrónica sea el Service1
  4. LazyMaterialization1;
  5. FServiceAFIP1.MakeABill(...);
  6. end;
  7.  
  8. procedure TAFIPServicesAdapter.LazyMaterialition1;
  9. begin
  10. if NOT Asigned(FServiceAFIP1)
  11. then FServiceAFIP1 := TAFIPService1.Create;
  12. end;

Por el patrón Creator, como así el Adapter asume la responsabilidad de crear. Él mismo es responsable de liberar dichos objetos delegados cuando sea el momento... ya sea porque la aplicación finaliza, o bien, porque quizá para renovar sea conveniente liberarlos en lugar de estar sobreescribiendo en sus atributos con los nuevos objetos que éstos requieran.

 

Al menos así lo entiendo yo.

 

Por cierto, este Adapter parece también ser una especie de Proxy Virtual. Otro patrón más... ¿Recuerda lo que te dije por mensaje privado? Observa como los patrones "vienen de a pares" ;)

 

Saludos,


  • 1

#4 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 06 mayo 2016 - 10:21

el servicio que hace la factura es uno solo:wsfev1.

Clases hijas no son tantas porque los webservices mas utilizados son: consulta en el padron y el que manda la factura.

por lo que a la clase login que ya esta publicada le agregamos dos hijas: loginwspn10 y loginwsfv1. Estas dos ultimas difieren en el string servicio.. una envia la solicitud para acceder al padron y otra para facturar. La idea mia era fabricar un objeto login: sino existe o si ya expiro creo uno nuevo. mas adelante publicare el codigo.

Ahora bien...lo que se me ocurre tambien: como sabe el metodo creador de objetos de login a priori para el servicio que sea cual es el tipo especifico de objeto a crear..

 

Es decir, cuando envio una factura con detalle y alicuotas etc... debo enviar al webservice wsfev1 el sign y token obtenido para el mismo..estos serian los atributos sign y token de la clase loginwsfv1. Previamente debo comprobar el atributo de expiracion la hora que expiran el sign y token anteriores, y tengo dos opciones: destruir el objeto y crear uno nuevo..o llamar un metodo actualizarSignToken.. que llame a los setter luego de probar la solicitud..

tambien podria hacerlo mas sencillo: la clase factura podria tener un metodo comprobarAutorizacion() que evalue la expirationtime y de ser necesario cree un nuevo certificado..

 

Pero mas adelante publicare mas codigo..


  • 0

#5 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 08 mayo 2016 - 07:12

Siempre aconsejo evitar el "patron" singleton

 

Es un diseño que esta roto desde el vamos (variable global, viola SOLID, acarrea estado, dificil de testear, inutil en multi-threading)

 

Si necesitas una sola instancia de cierta clase, creas una y listo :)

 

Entonces podria crear una instancia cuando se abre la aplicacion, o bien la primera vez que se utiliza el servicio de login para facturar creo una instancia, pero como manejo esa instancia en otros formularios? osea en toda la aplicacion?

 

Agrego: puedo tener un constructor privado con un metodo estatico, entonces si el objeto ya existe, ademas de no crear uno nuevo, puedo comprobar la fecha de expiracion, osea comparo la hora actual con la del atributo expiration, y si expiro llamo a un metodo que realize otra solicitud..


  • 0

#6 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 08 mayo 2016 - 09:52

Podes definir una variable global (malo). Me dirás, es lo mismo. En realidad no, ahí es problema del que usa la clase, pero no está mal diseñada

Otra forma es ir pasando esa instancia a quien la necesite, mediante los constructores o propiedades

Y si usas una interface ni problema por quien libera los recursos
  • 0

#7 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 23 mayo 2016 - 03:37

Bueno..sondeando por ahi encontre esto...

 

http://www.joseoc.es...-de-instancias/

 

es un array de singleton..se crea una unica instancia pero de varios objetos dependiendo cual se solicite...

 

En mi caso son los servicios de AFIP..

 

Saludos


  • 0