2013-08-25 14 views
12

È buona norma utilizzare Reflection nel modello di fabbrica?Utilizzo del riflesso nel modello di fabbrica

public class MyObjectFactory{ 
private Party party; 

public Party getObject(String fullyqualifiedPath) 
{ 
    Class c = Class.forName(fullyqualifiedPath); 
    party = (PersonalParty)c.newInstance(); 
    return party; 
} 
} 

PersonalParty implementa partito

+1

Esiste un caso serio per questo. In generale, considererei la riflessione come la mia ultima risorsa. Soprattutto per questo scopo. –

+0

Che dire di framework come JSf2.0 che usano annotazioni? Dovrebbero usare le API Reflection per creare un'istanza dell'oggetto durante il runtime? – Ullas

+1

Se si tratta di JSF, quindi taggare è così. –

risposta

9

Lo scopo del modello di fabbrica è quello di disaccoppiare po 'di codice dal tipo run-time di un oggetto che consuma:

// This code doesn't need to know that the factory is returning 
// an object of type `com.example.parties.SurpriseParty` 
AbstractParty myParty = new PartyFactory().create(...); 

Utilizzando il codice come questo, il PartyFactory è il solo responsabile per determinare o sapere esattamente quale tipo di runtime dovrebbe essere utilizzato.

Stai perdendo questo vantaggio passando il nome completo della classe di cui hai bisogno. Come è questo ...

// This code obviously DOES know that the factory is returning 
// an object of type `com.example.parties.SurpriseParty`. 
// Now only the compiler doesn't know or enforce that relationship. 
AbstractParty myParty = new PartyFactory().create("com.example.parties.SurpriseParty"); 

... qualcosa di diverso dal semplice dichiarare myParty come di tipo com.example.parties.SurpriseParty? Alla fine il tuo codice è altrettanto accoppiato, ma hai rinunciato alla verifica del tipo statico. Ciò significa che stai incorrendo meno di nessun beneficio mentre cedi alcuni dei vantaggi di Java che sono fortemente tipizzati. Se elimini com.example.parties.SurpriseParty il tuo codice sarà ancora compilato, il tuo IDE non ti darà alcun messaggio di errore e non ti accorgerai che c'era una relazione tra questo codice e com.example.parties.SurpriseParty fino al momento dell'esecuzione - questo è male.

Per lo meno, io vi consiglio di almeno modificare questo codice in modo l'argomento del metodo è un semplice nome di classe, non un nome completo:

// I took the liberty of renaming this class and it's only method 
public class MyPartyFactory{ 

    public Party create(String name) 
    { 
     //TODO: sanitize `name` - check it contains no `.` characters 
     Class c = Class.forName("com.example.parties."+name); 
     // I'm going to take for granted that I don't have to explain how or why `party` shouldn't be an instance variable. 
     Party party = (PersonalParty)c.newInstance(); 
     return party; 
    } 
} 

successivo: è cattiva pratica di utilizzare Class.forName(...)? Ciò dipende da quale sia l'alternativa e dalla relazione tra gli argomenti String (name) e le classi fornite da questo factory. Se l'alternativa è un grande condizionale:

if("SurpriseParty".equals(name) { 
    return new com.example.parties.SurpriseParty(); 
} 
else if("GoodbyeParty".equals(name)) { 
    return new com.example.parties.GoodbyeParty(); 
} 
else if("PartyOfFive".equals(name)) { 
    return new com.example.parties.PartyOfFive(); 
} 
else if(/* ... */) { 
    // ... 
} 
// etc, etc etc 

... non è scalabile. Poiché esiste un'evidente relazione osservabile tra i nomi dei tipi di runtime creati da questa factory e il valore dell'argomento name, è consigliabile prendere in considerazione l'utilizzo di Class.forName. In questo modo l'oggetto Factory è protetto dalla necessità di modificare il codice ogni volta che si aggiunge un nuovo tipo Party al sistema.


Qualcos'altro si potrebbe prendere in considerazione è utilizzando il modello AbstractFactory invece. Se il codice che consumano è simile al seguente:

AbstractParty sParty = new PartyFactory().create("SurpriseParty"); 
AbstractParty gbParty = new PartyFactory().create("GoodByeParty"); 

... dove ci sono un numero limitato di tipi di partito spesso si verificano, che vengono richiesti, si dovrebbe considerare di metodi diversi per i diversi tipi di soggetti:

public class PartyFactory { 

    public Party getSurpriseParty() { ... } 
    public Party getGoodByeParty() { ... } 

} 

...che ti consentirà di sfruttare la tipizzazione statica di Java.

Questa soluzione, tuttavia, significa che ogni volta che si aggiunge un nuovo tipo di Party, è necessario modificare l'oggetto di fabbrica, quindi se la soluzione riflettente o la AbstractFactory è una soluzione migliore in realtà dipende dalla frequenza e dalla velocità aggiungerò i tipi Party. Un nuovo tipo ogni giorno? Usa la riflessione. Un nuovo tipo di festa ogni decennio? Utilizzare un AbstractFactory.

+0

Grazie per la spiegazione dettagliata Sir .. – Ullas

+0

@ Ullas - Piacere mio. Aggiunto un altro paragrafo che enfatizza quando si dovrebbe usare la soluzione riflessiva contro quando si dovrebbe usare 'AsbtractFactory'. –

1

utilizzando la riflessione in questo modo (Class.forName) è quasi sempre segno di progettazione di applicazioni male. Ci sono alcuni tipi, dove il suo uso è OK, per esempio se stai facendo un qualche tipo di carico dinamico di librerie o plugin esterni.

1

È possibile utilizzarlo per un'API in cui si fornisce un'API e un configfile XML in cui gli utenti possono aggiungere i nomi di classe del proprio plug-in. Quindi, sì, si potrebbe usare questo

Problemi correlati