Design del codice Java per un client di servizio Web di Geocoder

2

Per favore, ti prego, se questo tipo di domanda è stata già chiesta. Sto avendo un dilemma con la progettazione di oggetti e la ricerca di aiuto di esperti qui per trovare il design corretto / migliore per un client di webservice. Allego un diagramma UML grezzo di seguito:

Ho scritto / aggiustato il codice Java, ma sono entrato nella progettazione / architettura degli oggetti. Sto scrivendo un client webservice in Java per integrare un servizio commerciale di convalida degli indirizzi di geocoding nella nostra applicazione. Il nostro è un software fiscale scritto in PowerBuilder in esecuzione all'interno di EAServer. Sto scrivendo il client del servizio web in Java, quindi può essere integrato con il client PB tramite CORBA.

Ho già fatto un servizio simile in precedenza per ottenere alcune informazioni GIS e questo è stato un po 'più semplice nella gestione del design solo XML sia per la richiesta che per la risposta. Ho gestito il recupero / l'invio di richieste e risposte nel controller stesso.

Ho iniziato a utilizzare lo stesso design e ho colpito un blocco stradale: il servizio web corrente gestisce sia XML che REST (tramite HTTP GET URL); in realtà, esistono 2 URL di servizio web, quello per la convalida degli indirizzi / Geocoding supporta XML o REST e l'altro per la ricerca di indirizzi utilizza solo REST. Voglio progettare una classe / interfaccia astratta di richiesta generica e il controller che può essere utilizzato per entrambi i servizi. Mentre cercavo di venire con le classi, mi sono imbattuto in un classico problema di design. Ora con la richiesta stessa può essere una stringa XML o un oggetto URI (per la richiesta REST), il mio approccio per ottenere la richiesta e inviarlo in Controller sembra imperfetto.

Devo creare l'oggetto Request stesso e inviare XML / REST stesso al Servizio esterno o dovrei in qualche modo riuscire a ottenere diversi tipi di Requests nel Controller e inviarlo da lì (usando getRequest, sendRequest)?

Inoltre, sto imparando a usare Design Patterns in Java. Che tipo di modello di progettazione sarebbe applicabile qui? Ho visto lo schema di comando suggerito per un cliente simile. Inoltre, è possibile applicare il pattern MVC qui?

Voglio solo farlo bene, prima di iniziare la codifica.

UPDATE:

Ilmiorecorddell'indirizzodainviarecomepartedellarichiestaè

publicclassAddressRecord{protectedStringAddressLine1;protectedStringAddressLine2;protectedStringCity;protectedStringState;protectedStringPostalCode;protectedStringCountry;...}

Eilmiooggettorichiestaè,

publicclassRequest{protectedAddressRecordrecords[];protectedArrayListactions;protectedArrayListcolumns;protectedPropertiesoptions;protectedStringtransmissionReference;protectedStringcustomerId;....}

Puòavereunooindirizzi(stopianificandodiinviarnesolounoperora).Permetteanchedispecificarelecolonneesattenecessarie,leazionidaeseguire,leopzioniecc.

ElamiaXMLRequestsiestende,

publicclassRequestXmlextendsRequest{..publicStringbuildRequest(){...}

EilmioproblemaèarrivatoquandohoprovatoafarelarichiestadiRESTallostessomodo,

publicclassRequestRESTextendsRequest{..publicURIbuildRequest(){...}

Asecondadellecolonnescelte,l'indirizzosaràconvalidatoeilservizioopzionalmentepasseràilLat/Longperl'indirizzo,setrovato.Unatipicarichiestadiindirizzoerispostapuòcontenereunoopiùdeiseguentirecord(informatoXML):

Richiedirecord

<Request><Actions>Check</Actions><Columns/><CustomerID>1234567890</CustomerID><Options/><Records><RequestRecord><AddressLine1>200MainSt</AddressLine1><AddressLine2/><City>LosAngeles</City><PostalCode>90012</PostalCode><State>CA</State><Country>USA</Country><CompanyName></CompanyName><EmailAddress/><FirstName/><FreeForm/><FullName></FullName><LastLine/><LastName/><PhoneNumber></PhoneNumber><RecordID>1</RecordID></RequestRecord><TransmissionReference/></Records></Request>

Recorddirisposta:Conterràrecorddiindirizziconvalidatieconformatostandard.

<ResponseRecord><AddressLine1>200MainSt</AddressLine1><AddressLine2></AddressLine2><City>LosAngeles</City><State>CA</State><CompanyName></CompanyName><EmailAddress></EmailAddress><NameFull></NameFull><PhoneNumber></PhoneNumber><PostalCode>90012</PostalCode><RecordExtras></RecordExtras><RecordID>1</RecordID><Reserved></Reserved><Results>AS01</Results><AddressExtras></AddressExtras><AddressKey>92688211282</AddressKey></ResponseRecord>

Probabilmentelostoallungandotroppo.Comesuggeritoda@Vladislav,potreiprobabilmenterenderebuildRequestnellarichiestaURIancherestituireunastringa,equestopotrebberisolverequestoproblema;questopuòportareaterminequestolavoro,mastocercandodiimparareafarlonelmodogiustodiidentificareoggettiedesign.

UPDATE2:@Vladislav,QuestoèquellocheavevoperunclientWebserviceprecedente.HannochiamatoilloroservizioGeoQuery,quindil'hochiamatoBoeQueryManager.Questosiqualificaperesserelaclasseditrasportoacuitistairiferendo?PensochequestosiailController.IlservizioGeoQuery_MyLAService,generatodaWSDL2Javapuòesserel'oggettoditrasportoacuisièfattoriferimento?Horifattoildiagramma,perilnuovoprogramma,perriflettereicambiamentichevedoperlamianuovacomprensionedeituoicommenti.Puoiperfavoreconfermarlo?

FYI,ouraddressvalidationisdonein3-parts-AddressValidation/Search,GeocodeandoncewegettheLat/Long,dotheinternalGISfunctiontogetcitylayers.Ialreadydidthe3rdpart,nowworkingonreplacingthe1stand2ndservices.

publicclassBoeGeoQueryManager{privatevoidinit(StringaUrlStr){try{URLendPoint=newURL(aUrlStr);GeoQuery_MyLAServiceservice=newGeoQuery_MyLAServiceLocator();geoq=service.getGeoQuery_MyLAcfc(endPoint);}catch(MalformedURLExceptionme){logger.error("BOEGIS", "", this.toString() + " - " +  "init", "Error initializing. " + me.getMessage());
      me.printStackTrace();
    } catch (ServiceException se) {
      logger.error("BOEGIS", "", this.toString() + " - " +  "init", "Error initializing Service. " + se.getMessage());
      se.printStackTrace();
    }
  }

  // Search by Address
  public String queryBoeGis(String aAddress) throws Exception {
    BoeXMLRequest lRequest = new BoeXMLRequest(aAddress, 0, 0, GISRequest.SEARCH_MODE_ADDRESS);

    return queryBoeGis(lRequest);

  }

  // Search by Lat/Long
  public String queryBoeGis(double aLatitude, double aLongitude) throws Exception {
    BoeXMLRequest lRequest =
        new BoeXMLRequest(GISRequest.REQUEST_BLANK_ADDRESS, aLatitude, aLongitude,
            GISRequest.SEARCH_MODE_LATLONG);

    return queryBoeGis(lRequest);

  }

  // 3. The controller is doing the Webservice call here. I just pass in 
  // the Request object into this. Controller is fully aware it's a XML
  // Request/Response.
  public String queryBoeGis(BoeXMLRequest aRequest) throws Exception {

    String respXML = "";
    String reqXML = "";

    requestCount++;
    try {
      reqXML = aRequest.getXml();

      if (aRequest.isModeLatLong()) {
        respXML = geoq.qByCoords(reqXML);
      } else if (aRequest.isModeAddress()) {
        // search by address (or both)
        respXML = geoq.addressValidationService(reqXML);
      }
      respXML = XMLDocument.cleanup(respXML);
      BoeXMLResponse boeResponse = new BoeXMLResponse(respXML);

      // To be able to get a flattened XML to be sent to the Legacy application
      if (adjustXML)
        respXML = XMLExtractor.getAdjXml(aRequest, boeResponse);

    } catch (Exception e) {
      e.printStackTrace();
      respXML = "";
    }

    // Otherwise, return the original XML
    return respXML;
  }
}

    
posta SamV 16.11.2015 - 21:58
fonte

1 risposta

2

Hai creato due gerarchie di classi parallele: Request con calcestruzzi ( XmlRequest , JsonRequest ecc.) e Response con calcestruzzi ( XmlResponse , JsonResponse ecc.).

Ma quello che penso che devi affrontare è un Request / Response come entità di business ( Request può essere semplice come una stringa, contenente l'indirizzo geocode per il nostro esempio e una Risposta - un array di due float - coordinate geografiche) e un numero di trasporti (Json, Xml ecc.).

Ogni trasporto ha il suo Request e Response codificatore / decodificatore dell'oggetto Request originale per rappresentare la richiesta e la risposta dai servizi web appropriati.

In questo modo separerai la tua logica di business da implementazioni concrete.

Il controller creerà un oggetto Request e quindi, in base ad alcune condizioni, scegli il trasporto appropriato affinché invii / ricevi dati. Transports serializza Request , comunica con servizi Web esterni, riceve e deserializza Response e lo restituisce al controller.

UPDATE:

Dopo aver visto i tuoi aggiornamenti sopra, vorrei che controllassi se hai bisogno di% discendenti di classeRequest. Lo schema di richiesta / risposta è altamente personalizzato in base al trasporto. Perché non avere una sola gerarchia di classi Transport , che riceverà il tuo oggetto Request e restituirà Response ?

Transport gestirà tutti gli URI o qualsiasi altro dettaglio del protocollo interno.

UPDATE 2:

just curious: while learning OO, I keep hearing about making objects self contained. This is why I made XMLRequest etc, thinking that's the only one that knows about the request.

Bene, è vero. Si tratta di SRP in realtà. Se un'implementazione è molto semplice, puoi assegnare la responsabilità di "trasporto" a una classe Transport . Se l'implementazione diventa o sta pianificando di diventare complessa, trasformi Transport in un modulo, crea una facciata per esso e poi assegna le responsabilità di "gestore di richieste" e "gestore di risposta" alle classi, all'interno di questo modulo.

Quando eseguo la progettazione OO, in realtà sto cercando di mantenere il sistema comprensibile e separabile a tutti i livelli di "zoom": layer - > modulo - > class - > membro della classe.

Immagino che il tuo secondo diagramma sia molto meglio, ma offuschi le responsabilità tra le classi. Il controllore dovrebbe creare Request oggetto e usare un qualche tipo di fabbrica per istanziare Transport . In questo modo, i dettagli del trasporto sono nascosti dal controller. Dovrebbe conoscere abstract Transport class / module senza entrare nei dettagli sulla sua implementazione.

    
risposta data 17.11.2015 - 12:48
fonte

Leggi altre domande sui tag