Domanda di progettazione orientata agli oggetti

6

Ho una lunga esperienza nel mondo procedurale e sto programmando / mantenendo il codice OO anche in varie lingue. Ora entra nel design OO e senti i dolori di identificare gli oggetti da zero. Ho letto diversi libri, articoli, ecc. Su OO. Spesso si fermano con gli esempi Person, Employee. Identificarlo e farlo nel modo giusto in un progetto del mondo reale solleva diverse domande.

Questa è una sorta di domanda di follow-up dalla mia precedente recensione di design domanda . Dì, ho un oggetto come sotto:

public class AddressRecord {
  protected long RecordID;
  protected String AddressLine1;
  protected String AddressLine2;
  protected String City;
  protected String State;
  protected String PostalCode;
  protected String Country;
  protected String FirstName;
  protected String LastName;
  protected String FullName;
  protected String PhoneNumber;
  protected String EmailAddress;
  protected String CompanyName;
  ..
  /* related to my question below */
  public String extractXml() {}
  public HashMap extractHash() {}
  public String extractJson() {}
  ...
}

Ora voglio estrarre il campo / i valori in una tabella hash o XML (formato proprietario) o JSON senza ricorrere a librerie come JAXB. Scriverò alcuni metodi (ad esempio, extractXml, extrachHash, extractJson) per estrarre campi specifici nel formato di destinazione.

La mia domanda è dove dovrebbero essere questi metodi di estrazione / conversione? Sulla base di una certa esposizione ai libri e ai consigli di progettazione OO, supponevo che potessi avere questi metodi proprio all'interno di questa classe.

@Vladislav ha detto che dovrebbero essere fuori, come nel controller. In qualche modo capisco, ma sono curioso di sapere perché? Inoltre, se voglio isolare questa logica di estrazione dal codice del controller, posso creare una classe facendo proprio questo? Mi piace,

public class AddressRecordXml {

   public static String extractXml(AddressRecord rec)
   {

   }

   ...
}

e quindi usarlo nel controller come,

...
AddressRecord rec = new AddressRecord();
String xmlStr = AddressRecordXml(rec);
...
String resp = transport.process(xmlStr);
...

Nota: so che esistono librerie come JAXB ecc. per aiutare a serializzare oggetti in XML, ecc. Non posso ancora usarli. Sto lavorando con Java 1.4 all'interno di un vecchio Sybase EAServer (il linguaggio di programmazione principale è PowerBuilder) e pone molte restrizioni. Lo stesso motivo per HashMap, no Generics ecc.

    
posta SamV 20.11.2015 - 23:53
fonte

5 risposte

2

Gli esempi di OO tendono a fermarsi con Person, Employee perché il loro obiettivo è dimostrare il principio della modellazione delle entità del mondo reale. Naturalmente, queste entità sono piuttosto inutili da sole: per fare qualcosa di utile con loro è necessario usarle in qualche sistema più grande, e progettare un tale sistema in modo OO non è facile da descrivere in termini di semplice, esempi facili da inghiottire.

Non esiste una risposta chiara alla domanda su dove dovrebbero andare questi metodi. Un purista potrebbe dire che il metodo di estrazione xml dovrebbe andare in una sorta di gestore che si occupa specificamente di xml e che è incluso solo in un sistema che si occupa di xml. Quindi, un sistema diverso, che non avrebbe a che fare con xml, non includerebbe alcun codice di generazione xml. Inoltre, un sistema diverso, che richiederebbe una diversa rappresentazione xml, includerebbe solo il codice che si occupa di quella rappresentazione, invece di essere complicato con una routine di estrazione xml predefinita e inutilizzata nell'oggetto dati e un'altra routine di estrazione xml altrove. p>

Ma ovviamente è molto accademico. Mettere la routine di estrazione xml nell'oggetto dati è un compromesso pragmatico, che semplifica le cose fin dall'inizio e, se mai si verifica la necessità di una configurazione di sistema diversa, è possibile rifattorizzarla facilmente dall'oggetto dati e in alcuni responsabile.

Nota 1: la tendenza attuale è di evitare di chiamare "gestori". Quindi li chiamano "controller" invece. Questo è in realtà ridicolo.

Nota 2: spero davvero che tu abbia un compenso monetario significativo per le insalubri condizioni lavorative di dover lavorare con Java 1.4; in caso contrario, si prega di prendere in considerazione di lasciare quel lavoro. Personalmente, non prenderei nemmeno in considerazione nessuna versione di java precedente alla 1.8.

    
risposta data 21.11.2015 - 00:24
fonte
2

Come l'OP ha correttamente ipotizzato, a volte OO è solo OO per l'amor di OO. Vedi questo "antipattern" ogni volta che vedi un pacchetto "util". aaaaannnd .... sono in OGNI progetto. A volte ha senso estrarre le comuni funzioni statiche banali in raccolte di utilità, che hanno una sorprendente somiglianza con la programmazione funzionale. Se non è etichettato come "util", probabilmente è etichettato come "helper".

Inoltre, mi vergogno un po 'quando la gente si rifiuta di usare il codice della libreria per questa roba ... quale parte di "questo codice ha subito 500.000 ore di test unitari nella comunità degli utenti" non ti sta facendo appello?

    
risposta data 21.11.2015 - 00:45
fonte
2

I was assuming I could have these methods right inside this class, but ... mentioned that they should actually be outside, like in the controller.

Entrambi i disegni sono possibili, e quale è più adatto al tuo caso, dipende. Per i programmi più piccoli, con solo una manciata di oggetti dati, in cui è necessaria solo una funzione di conversione come extractXml e nessuna delle altre, è possibile decidere di inserire questa funzione direttamente nella classe. Quando il tuo programma diventa più grande e la tua classe AddressRecord potrebbe avere diverse altre funzioni, mettere funzioni come extractXml o extractJson in una classe separata come AddressRecordXml ti aiuterà a dare al tuo programma più struttura e a mantenere il tuo AddressRecord più universale.

Tuttavia, quando hai molte di queste classi di dati, il tuo design migliorerà davvero se puoi implementare una versione generica di extractXml(object) , non specificatamente un metodo di AdressRecordXml , ma di una classe universale come XmlExtractor . Anche in Java 1.4, è disponibile una riflessione, che ti permetterà di implementare tale classe in modo generico.

Al tuo commento: quando inizi con un piccolo programma, potresti posizionare extractXml in AddressRecord direttamente. Quando il tuo programma cresce nel tempo, devi rifattorizzare qualsiasi parte del codice in classi separate che diventano altrimenti "troppo complesse". Il trucco è di non perdere il punto in cui effettuare il refactoring e di iniziare non appena il codice inizia a violare i principi SOLID. Questo è IMHO l'unico modo per affrontare correttamente il "futuro": creare un design per "il futuro" senza conoscere il futuro sempre porta a decisioni di progettazione sbagliate.

    
risposta data 21.11.2015 - 00:25
fonte
1

Dipende dalla complessità, ma di solito creo una o più classi di input / output.

Generalmente creo un'interfaccia AddressRecordInput che fornisce un metodo read() che restituisce un AddressRecord e un'interfaccia AddressRecordOutput che fornisce un metodo write(AddressRecord) . Fornirei quindi implementazioni di queste interfacce, come AddressRecordXMLInput , AddressRecordXMLOutput , AddressRecordJSONInput e AddressRecordJSONOutput , ciascuna con un costruttore appropriato. Per il costruttore, prenderei in considerazione qualche tipo di lettore, scrittore o flusso IO esistente.

Lo ripeto per tutte le tue classi di modelli di dati. Queste classi di IO possono utilizzare librerie di terze parti, come JAXB (per XML) o Apache POI (per i formati I / O da e verso Microsoft Office).

Lo svantaggio è che per i modelli di dati di grandi dimensioni esistono molte classi. Tuttavia, tendono ad essere facili da capire e testare.

    
risposta data 21.11.2015 - 00:18
fonte
1

C'è una chiara separazione delle preoccupazioni :

1) Hai i tuoi dati ( DTO ) AddressRecord

2) Hai la necessità di rappresentare il modello in diversi modi

Detto questo, ci sono (almeno) due oggetti necessari: (1) il DTO stesso (2) un modulo di uscita

Il modo OO tipico / ortodosso per implementarlo è tramite schema di strategia . Il meccanismo di gestione dei diversi formati di output viene sottratto in un'implementazione dell'interfaccia: per fare un esempio, chiamiamolo AddressWriter , con un metodo semplice write() . L'implementazione concreta dell'interfaccia incapsula mechanism . Il machanism dell'estrazione, la conversione in JSON / XML è stimolato lì. DTO non ha bisogno di sapere JSON o XML , né deve sapere quali valori sono per quale formato interessante. Non è la sua preoccupazione.
Il vantaggio è chiaro: per astrazione ottieni la libertà di implementare diversi formati senza modificare o rompendo codice esistente: hai solo bisogno di un'altra implementazione del meccanismo.

Potresti chiamarlo altamente acamdemic - Io lo chiamo design appropriato .

    
risposta data 21.11.2015 - 23:36
fonte

Leggi altre domande sui tag