È meglio esporre o nascondere la dipendenza in OOP?

8

Diciamo che ho un oggetto A, che è troppo grande (con troppi metodi e variabili). Quindi, lo suddivido in oggetti più piccoli. Dopo di ciò, ho Object A, B e C. Ovviamente, l'oggetto A è di classe A, l'oggetto B è di classe B e così via.

Sfortunatamente, ho delle dipendenze: A dipende da B, e B dipende da C. In definitiva, userei solo l'Oggetto A. Da quella situazione, ho due scenari:

  1. crea un oggetto C in classe B e crea un oggetto B in classe A. Quindi, crea l'oggetto A nel metodo principale.
  2. crea gli oggetti A, B e C tramite l'iniezione delle dipendenze nel metodo principale.

In generale, è meglio utilizzare lo scenario n. 1 per nascondere la dipendenza o lo scenario n. 2 per esporre la dipendenza?

A proposito, preferirei vedere il codice Java nel caso qualcuno volesse fornire un esempio di codice.

    
posta Rin Minecraft 01.07.2016 - 01:31
fonte

3 risposte

10

Is it better to expose or hide dependency in OOP?

È meglio fare entrambe le cose.

Prima di spiegarmi, permettimi di esplorare i problemi con le tue proposte.

Let's say I have an object A, which is too big(having too many methods and variables). So, I break it down to smaller objects.

Questo è buono. Rompa sempre gli oggetti fino a quando non hanno una sola responsabilità, cioè, una sola ragione per cui potrebbero mai cambiare. Ciò non significa che possano avere un solo metodo o dipendenza, ma dovrebbero concentrarsi su un'idea.

  1. create an Object C in Class B, and create an Object B in Class A. Then, create Object A in main method.

A seconda di qualcosa non è come sapere come crearlo. Questa idea richiede che A (e B) facciano entrambe le cose. Non abbiamo rotto A perché lo stava facendo molto in primo luogo?

Creerò eccezioni per oggetti valore (Stringhe e simili) ma in generale mi piace separare l'uso dalla costruzione.

  1. create Object A, B, and C through dependency injection in main method.

Questo suona bene, A usa B ma non lo costruisce. B usa C ma non lo costruisce. Per quanto riguarda le applicazioni così grandi che hanno bisogno di più di 26 lettere dell'alfabeto per dare loro nomi univoci? Main può diventare improvvisamente un posto occupato.

Ci sono una serie di framework per le dipendenze che ti piacerebbero risolvere questo problema per te se vendi la tua anima a loro. Cioè, diventa dipendente da loro.

Se sei un po 'testardo puoi usare schemi creativi. I GoF funzionano ancora. Puoi anche usare i modelli creazionali più recenti, il builder Josh funziona bene in Java e in altre lingue con problemi con i nomi. Ci sono altri costruttori che ti consente di avere incredibili livelli di controllo sulla creazione se sei disposto a inserire lo sforzo .

Questo arriva fino alle lingue specifiche del dominio interno (iDSL). Questi ti permettono di definire essenzialmente il tuo linguaggio all'interno di Java (o quasi tutti gli altri) e il compilatore di Java lo compilerà per te. Questo ti dà il controllo completo della creazione e dell'iniezione di oggetti. Ma può richiedere un lavoro considerevole. Calpesta leggermente qui perché questa tana di coniglio è profonda.

Questo mi porta alla mia raccomandazione "fai entrambe le cose".

Un'abitudine di successo che ho sviluppato è accettare tutto come un'iniezione nei miei oggetti comportamentali, ma costruirli con iniettori specializzati che conoscono buoni valori predefiniti che richiedono poche o nessuna iniezioni. Puoi avere, diciamo, 5 iniettori della stessa classe che lo costruiscono in 5 modi diversi. Puoi avere un iniettore che costruisce 5 oggetti comportamentali tutti ben cablati insieme. È anche possibile iniettare iniettori negli iniettori e farli intrecciare un grafo di oggetto comportamentale.

Identifica i buoni valori predefiniti se esistono e usa quelli per creare il tuo iniettore di base. Alcuni tendono a usare metodi statici come iniettori, ma possono essere essi stessi oggetti in piena regola. In realtà è più potente.

Ecco come "fai entrambi". Le dipendenze sono esposte per oggetti comportamentali. Gli oggetti creazionali nascondono le dipendenze, eseguendo il lavoro che altrimenti sarebbe diffuso su tutto il main.

Ciò che risolve è una tensione fondamentale tra le buone API della macchina e l'usabilità umana. Ciò che rende una classe iniettabile flessibile non costituisce un buon costruttore di classe utilizzabile umano. Quando mi ritrovo a voler rendere più semplice la costruzione di un oggetto, raggiungo un altro oggetto per farlo funzionare. Non distraggo l'oggetto del comportamento con i suoi dettagli di creazione.

Ho usato diversi framework di dipendenze per le iniezioni e sono arrivato alla conclusione che tutto quello che hanno davvero finito per me stava esprimendo la creazione di oggetti in un'altra lingua (sia xml che @annotations). Risulta che puoi fare tutto in java. Scegli i nomi migliori in modo che le persone sappiano in che tipo di classe si trovano ed è altrettanto mantenibile.

Fatto in questo modo, un look in main mostrerà il collegamento di alcuni grafici di oggetti in scatola e una chiamata a un metodo su uno di questi oggetti per iniziare il tutto ticchettando. Questo è l'unico posto in cui mixo la creazione e l'utilizzo. Devi farlo da qualche parte.

Come tutto ciò può essere esagerato, ma con il giusto equilibrio rende la codifica un po 'più semplice.

    
risposta data 01.07.2016 - 05:33
fonte
1

Ciò che hai detto mi fa pensare perché l'Oggetto A è così grande.

Invece di pensare alle dipendenze e all'iniezione, mi concentrerei sulla composizione sull'ereditarietà che consente la creazione di oggetti in ritardo solo nel tempo solo se necessario.

Se sei preoccupato per l'esposizione delle dipendenze, potrebbe essere gestita esponendo le interfacce invece delle classi interne.

    
risposta data 01.07.2016 - 04:41
fonte
0

Dipende. Se B e C supportano solo A e sono inutili / privi di significato in qualsiasi altro contesto, nascondili (incapsulandoli in A). Se sono entità che hanno già qualcosa nel tuo dominio problematico di primo livello, indipendentemente dall'uso di A, tu come utente potresti volerle creare tu stesso e iniettarle per una maggiore flessibilità.

Esempio: classe EmailSender.

Scenario 1 È necessario inviare e-mail Non ti interessa il modo in cui viene inviata l'email, vuoi fornire From, To, Subject e BodyText e farla finita. Iniziando una discussione e aprendo una presa, scegliendo una porta, non ti interessa, è solo rumore per te. Tutto quello che ti interessa è ottenere una notifica su alcuni cambiamenti di stato nel tuo sistema. Quindi fai il metodo 1.

Scenario 2 È necessario inviare e-mail Questa volta ti preoccupi dei dettagli perché la tua applicazione è un mailer di massa e hai bisogno del controllo per impostare la priorità, l'uso della memoria e le informazioni di routing. Quindi fai il metodo 2.

    
risposta data 02.07.2016 - 19:58
fonte

Leggi altre domande sui tag