2009-03-09 8 views
14

Provenendo da uno sfondo C++ devo padroneggiare la complessità del mondo Java e dei suoi framework. Guardando il framework primaverile per DI I sono trovando difficile credere che io debba rendere ogni funzione setter che sarà soggetta a DI pubblico. Questo requisito non infrange il principio di nascondere le informazioni?Non si nasconde l'interruzione dell'input della dipendenza da Spring?

Ovviamente voglio che Spring sia in grado di impostare alcune parti private delle mie classi , ma certamente NON voglio che ogni classe client sia in grado di eseguire lo stesso .

Cosa mi manca qui?

risposta

6

Se si utilizza il codice per le interfacce, è necessario esporre i setter sulle implementazioni. Quando si iniettano le interfacce in altre parti del sistema, non possono accedere ai dettagli di implementazione o allo stato degli oggetti.

+1

Questa risposta implica che "codifica per interfacce" significa che ogni classe deve implementare un'interfaccia separata. Questo non è ciò che il principio, come descritto nel libro GoF, significa. In realtà, si applica solo ai casi in cui è necessario o già in uso due tipi di oggetto distinti, uno per l'astrazione (interfaccia) e un altro per un'implementazione di tale astrazione. –

+0

Penso che sia probabile che le classi che devono essere iniettate l'una nell'altra in una comune applicazione Spring siano classi ** service **, come 'Dao's ecc. Ho scoperto che un gran numero di queste potrebbe presumibilmente hanno implementazioni alternative –

+1

Sì, quando si hanno più implementazioni si applica il principio "codice per l'interfaccia, non per l'implementazione". Ma dire cose come "se si codifica per interfacce ..." senza un chiaro contesto è fuorviante e può essere facilmente interpretato male da sviluppatori meno esperti.L'uso eccessivo di interfacce separate provoca gravi danni, IMO. –

15

Sono d'accordo con il vostro punto: è per questo che preferisco l'iniezione del costruttore.

+2

+1 sull'iniezione costruttore. Esprime le dipendenze molto più forti e rimuove la necessità di setter "divertenti" – flq

+0

Iniezione costruttore ++: una volta creato un oggetto, deve essere pronto per l'uso e in uno stato coerente. – Kalecser

+2

Non tutte le proprietà potrebbero essere richieste per il corretto funzionamento della classe. In tal caso, li inietto sempre tramite i setter –

5

Si (può) si deve fare un setter, che informerà l'esterno di alcuni dei propri dettagli interni, ma non c'è bisogno di fare un getter. Quindi stai rivelando alcune informazioni, ma non troppo; non è veramente utile per nulla se non per lo scopo previsto.

Inoltre, consiglierei semplicemente di utilizzare le annotazioni e @Autowired, nel qual caso non è necessario creare un setter pubblico.

+0

+1 - sostenere le annotazioni, ove possibile, è una buona cosa. Sto provando a fare il salto da solo ora, ma è difficile rompere questa abitudine XML. – duffymo

3

Se si utilizzano le annotazioni a molla (@Autowired) è possibile DI membri privati.

Se si procede per accoppiamento libero e testabilità (unità), a mio avviso le molle DI scoppiano informazioni che non devono essere nascoste.

0

Suppongo che sia un compromesso. Riduci le dipendenze cablate, ma esponi potenzialmente il coraggio della tua implementazione. Con le giuste astrazioni, puoi ridurre anche questo, ma poi aumenti la complessità della base di codice (ad esempio, avendo una "Connessione" generica che potrebbe essere una connessione LDAP o una connessione SQL).

Personalmente, non penso che utilizzare l'iniezione del costruttore sia d'aiuto, perché è più concettuale.

Dovrò controllare @Autowire, tho '.

tj

1

ho avuto fondamentalmente la stessa domanda qui:

Encapsulation in the age of frameworks

Penso che la risposta potrebbe essere l'iniezione del costruttore. Esporre le tue proprietà con setter rende davvero difficile ecapsulare qualsiasi cosa e mantenere un buono stato dell'oggetto.

1

Mai usato @Autowired, tendo a come utilizzare i parametri nei costruttori ma a volte è difficile capire cosa significano i parametri, specialmente se si hanno molti parametri - in tal caso, preferisco usare l'approccio "Builder" descritto in Effective Java. Il costruttore riceve l'oggetto build (che ha setter) e si costruisce con esso. Gli attributi iniettati della classe sono finali (immutabilità), la classe "Builder" contiene setter ma non getter (non ha bisogno di come la dichiariamo come una classe interna della classe che viene costruita), e nessun setter ha bisogno ad essere creato solo per la primavera:

<bean id="runnable" class="MyClass"> 
    <constructor-arg> 
    <bean class="MyClass$Builder"> 
     <property name="p1" value="p1Value"/> 
     <property name="p2" value="p2Value"/> 
     <property name="p3" value="p3Value"/> 
     <property name="p4" value="p4Value"/> 
    </bean> 
    </constructor-arg> 
</bean> 

codice classe:

public class MyClass { 
    private final String p1; 
    private final String p2; 
    private final String p3; 
    private final String p4; 
    public MyClass(Builder builder) { 
     this.p1 = builder.p1; 
     this.p2 = builder.p2; 
     this.p3 = builder.p3; 
     this.p4 = builder.p4; 
    } 

    ... 

    public static class Builder { 
     private String p1; 
     private String p2; 
     private String p3; 
     private String p4; 
     public void setP1(String p1) { 
     this.p1 = p1; 
     } 
     ... and so on 
    } 
} 
0

non concordato con il punto che la primavera si rompe l'incapsulamento. Anche se hai pojo in cui hai ottenuto e esposto in classe e terze parti consumano il tuo barattolo, è comunque probabile che il consumatore di jar faccia lo stesso che è possibile con la configurazione del bean Spring. (vero per qualsiasi altra lingua delle OOP)

Spring fornisce solo il modo che è possibile eseguire tramite il codice e che il controllo è stato spostato dal codice (IOC).

Consumatore (si consideri che un altro programmatore utilizza la propria libreria), crea bean tramite la configurazione di primavera, sempre il codice ha il controllo. Nessun organismo ti impedisce di convalidare l'input fornito dall'utente (il framework primaverile del CIO passa anche attraverso lo stesso codice che viene eseguito da un'altra classe che chiama il tuo setter) nel setter.

public void setAge(int age) { 
if (age < 0) { 
    throw new AppException("invalid age!"); 
} 
this.age=age; 
} 
0

E questo è un altro motivo io preferisco Guice;) Sia Guice e Spring implementare JSR 330 DI spec ma con Guice posso iniettare nei miei campi di istanza private senza setter un io veramente piace iniezione costruttore come è sembrato più difficile da refactoring. È anche molto più digitando per non molto valore a mio modesto parere.

tardi, Dean

Problemi correlati