2015-12-09 14 views
5

Sto lottando un po 'con il lancio di classe. Lasciatemi ambientare la scena. Ho un codice Java server che usa un livello di servizio e orchestratore. Una richiesta arriva nel livello di servizio in un formato di bean (classe java allineata con la vista front-end), e poi ho un gruppo di classi domainBeanMapper che prendono un oggetto in formato bean e lo traducono in un oggetto formato dominio. Ad esempio, UserBean ha una dataObBirth rappresentata da una stringa, mentre User ha la dataOfBirth rappresentata da una Data, quindi UserMapper.java renderà la stringa della data in un oggetto data. Quindi per ogni oggetto nel sistema ho un * .java, * Bean.java e * Mapper.java (User.java, UserBean.java, userMapper.java).Java: eseguire il cast su un'interfaccia, quindi scoprire che tipo di fuso è

in applicationContext tengo il rapporto da ogni oggetto al loro mapper, come questo:

<util:map id="domainBeanMappers"> 
    <entry key="UserBean" value-ref="userMapper" /> 
    <entry key="User" value-ref="userMapper" /> 
..... 

e poi ho definire il mapper:

<bean id="userMapper" class="com.me.mapping.UserMapper" parent="baseDomainBeanMapper"/> 

io chiamo il mapper di fagioli dominio come questo da il mio livello di servizio:

UserBean userBean = (UserBean) getDomainBeanMapper().mapDomainToBean(user); 

Nella corsa di questo codice trovo il mapper obje ct che voglio in questo modo:

DomainBeanMapper mapper = findApplicableMapper(myObject.getClass().getName()); 
    if (mapper == null) { 
     mapper = findApplicableMapper(myObject.getClass().getSimpleName()); 
    } 

dove findApplicableMapper funziona così:

private DomainBeanMapper findApplicableMapper(String string) { 
    return domainBeanMappers.get(string); 
} 

Negli ultimi anni, questo ha funzionato come un fascino. Per qualunque oggetto io desideri nel sistema posso facilmente selezionare il relativo mapper e quindi tradurre dal mio formato bean in formato dominio e viceversa, in base alla chiamata .getClass() di qualsiasi istanza.

Ora ho un nuovo requisito che mi dà problemi. Voglio essere in grado di tradurre dal mio oggetto Utente a diversi sottooggetti in base a un parametro. Quindi per alcune chiamate, voglio solo l'id, firstName e lastName back. Per le altre chiamate voglio più campi, ma ancora non l'intero oggetto, e poi per alcune chiamate voglio che l'intero oggetto venga restituito come prima. Non voglio scendere il percorso degli oggetti secondari e finire con UserLight, UserLightWithName, UserLightWithNameButNoAddress, ... argh nightmare.

Così invece speravo di creare un gruppo di interfacce che rappresentassero "viste". Quindi la richiesta arriva con il ViewType di Basic, e ciò significa che voglio i dettagli e l'indirizzo personale dell'utente. Così ho scritto un'interfaccia chiamata UserBasic, ha ottenuto l'utente per la sua attuazione, e ha aggiunto una mappatura da UserBasic a UserBasicMapper, e da UserBasicBean a UserBasicMapper, nella speranza che avrei potuto fare la chiamata di tradurre in questo modo:

UserBasicBean restrictedUserReturn = (UserBasicBean) getDomainBeanMapper().mapDomainToBean((UserBasic)user); 

ma questo non funziona perché getClass() restituisce sempre la classe delle istanze, non l'interfaccia su cui è stato eseguito il cast. Immagino di poter sempre aggiungere un altro parametro alla chiamata mapDomainToBean, che è la classe che voglio usare, ma il codebase è abbastanza massiccio e dovrò toccare ogni chiamata se apporto questa modifica.

Quindi in sostanza sto cercando un modo per trasmettere un'istanza a un tipo di interfaccia e quindi trovare quel tipo di interfaccia? È possibile??

croci dita ...

+0

Perché non vuoi l'intero oggetto? –

+0

è un requisito di sicurezza. alcuni utenti del sistema possono vedere solo determinate parti di oggetti. – Margaret

risposta

3

Invece di creare interfacce implementate dall'utente, perché non creare classi proxy che rappresentano le versioni limitate? Ad esempio,

class UserBasic { 

    private User user; 

    public UserBasic(User user) { 
     this.user = user; 
    } 

    public String getFirstName() { 
     return user.getFirstName(); 
    } 
    ... 
} 

Quindi è possibile aggiungere un getUser() { return user; } per ottenere la piena istanza indietro.

In questo modo si dovrebbe essere in grado di mantenere tutto il resto lo stesso e fare un compromesso per l'interfaccia di classe.

+1

Ooh, questo è bello !!! Avrà la stessa funzionalità e non dovrò modificare il codice domainBeanMapper. UserBasic potrebbe anche avere un metodo getUser() per consentirmi di eseguire il mapping nella direzione opposta, per le richieste che forniscono la vista dell'oggetto secondario. Sì, è fantastico! – Margaret

+0

ha, eccellente, hai aggiunto il pezzo getUser mentre stavo scrivendo il mio commento.Grazie mille per il tuo tempo! – Margaret

+1

Felice di aiutare !! @Margaret – ChiefTwoPencils

0

non sono sicuro, ma è possibile utilizzare instanceof parola chiave per verificare quale tipo di oggetto che è.

+1

purtroppo che non è in realtà andando a lavorare come ho dovuto dire \t se (myObject instanceof UserBasic) { \t \t mapper = findApplicableMapper ("UserBasic"); \t} else if (myObject instanceof AnotherView) { \t \t ..... \t} che sarebbe davvero sporca il mio codice. grazie per il pensiero però – Margaret

+0

quello che sto cercando è un modo per sfruttare il codice dietro l'implementazione di instanceOf per scoprire di cosa myObject è un'istanza di. sembra sciocco che questo non sia disponibile – Margaret

0

Si può fare qualcosa di simile a scrivere alcuni metodi che si differenziano con il tipo paramenter, esempio:

public class Test 
{ 

    public static void n(Number n) { 
     System.out.println("Number"); 
    } 

    public static void n(Integer n) { 
     System.out.println("Integer"); 
    } 

    public static void main(String[] args) 
    { 
     n(3); //will call the n(Integer n); 
     n((Number)3); //will call the n(Number n); 
    } 
} 

Quindi sì, si può scoprire quale tipo si è colato a rendendo più metodi ogni corretto tipo di parametro di prendere e quindi elaborarlo di conseguenza per digitare.

+0

sfortunatamente non credo di poter usare questo percorso. Avrò il mio oggetto implementare più interfacce per le diverse viste. Tutti saranno insiemi sovrapposti dei getter e setter rilevanti delle variabili membro. per esempio. L'utente implementa UserBasic, UserLight, UserLocation. quindi, se utilizzo i controlli instanceof, restituirà true per tutti, poiché l'oggetto User li implementa tutti. invece di controllare quale tipo ho appena lanciato. Ha senso? Ho bisogno di trovare l'interfaccia specifica che è stata appena lanciata. – Margaret

0

L'interfaccia non rappresenta la vista, definisce un comportamento. Credo che hai bisogno di un qualche tipo di fabbrica (ckech questi collegamenti per l'ispirazione https://en.wikipedia.org/wiki/Factory_method_pattern, https://sourcemaking.com/design_patterns/abstract_factory) qui (o costruttore) Se dici qualcosa su 'sub-oggetti' - cercare di estendere classe UserBean

class BaseUserBean extends UserBean {} 
class AnotherUserBean extends UserBean {} 

put la roba comune per tutti gli utenti in classe di base e qualcosa di veramente specifico per ciascuno dei vostri sub-utenti diciamo in classi per bambini e poi

UserBean u = getDomainBeanMapper().mapDomainToBean(user); 

...

//method mapToDomain should check your param and return the type you need 
//ViewType can be a part of user or a separate param 
UserBean mapDomainToBean(User user, ViewType vt) { 
    if (vt == ViewType.BASE) { 
     BaseUserBean obj = BaseUserBean(); 
     // mapping here (set fields you need) 
     return obj; 
    } 

    if (vt == ViewType.ANOTHER) { 
     AnotherUserBean obj = AnotherUserBean(); 
     // mapping here (set fields you need) 
     return obj; 
    } 
    ... 
} 
+0

questo è certamente possibile, grazie, ma cambiando la mappa, la firma di DominoToBean influirà su centinaia di punti e non c'è attualmente tempo di test di regressione sull'intero sistema con troppa attenzione. – Margaret

Problemi correlati