All'improvviso ho un po 'di crisi OO. Negli ultimi due anni ho fatto un uso abbastanza buono degli oggetti Singleton. Li ho usati in molti posti.Buona progettazione OO - The Singleton Design Pattern
Ad esempio, nella progettazione di un'applicazione MVC Java, creo una classe 'SystemRegistry' di Singleton per archiviare il modello e visualizzare le classi (ho lavorato solo su semplici app e non è mai emersa la necessità di più viste) .
Quando creo il mio modello e visualizzare gli oggetti (che non erano single, solo oggetti normali), mi piacerebbe fare qualcosa di simile:
SystemRegistry.getInstance().setModel(model);
Nelle mie classi controller (che erano i gestori di eventi più o meno per diversi elementi GUI), avrei avuto accesso alla vista o modello come segue:
SystemRegistry.getInstance().getView();
non avrei mai utilizzare la classe SystemRegistry nella porzione modello della mia app, ma sarebbe, a volte, usarlo a mio avviso per accedere (ma raramente, se mai, per modificare) le informazioni dal modello.
Da quello che ho letto (in particolare Steve Yegge's article), questo sembra un modo scadente per progettare la mia applicazione. Qualche idea su modi migliori per strutturare il mio codice.
Inoltre, un altro aspetto di come disegno le classi, che possono o non possono essere correlate a Singletons, è l'uso di classi di tipo Manager. Un esempio è un (molto semplice) motore di gioco basato su OpenGL che ho creato in C++.
La classe principale era GameEngine. Era la classe over-arcing che immagazzinava un gruppo di Manager e gestiva il ciclo principale e cosa no. Alcuni dei gestori memorizzati in questa classe erano cose come: ObjectManager, RenderingManager, LightingManager, EventManager (include input), HUDManager, FrameRateManager, WindowManager, ecc. Probabilmente ce n'erano anche altri.
Fondamentalmente queste classi gestivano i diversi aspetti del motore di gioco. I nomi sono piuttosto semplici, quindi dovresti essere in grado di avere una buona idea di come vengono utilizzati.
Ora, questo doveva essere una base riutilizzabile che potrei utilizzare in diversi progetti con la necessità di modificarlo idealmente.
In ogni nuovo gioco, vorrei creare un'istanza del GameEngine come variabile di classe (la maggior parte della logica di gioco era memorizzata in una singola classe) e impostare i diversi gestori (ad esempio, il caricamento della finestra co -ordina o illumina i dettagli da un file, impostando l'FPS, ecc.). Per registrare un oggetto nel ObjectManager vorrei fare qualcosa di simile:
Player player = new Player();
gameEngine.getObjectManager().addObject(player);
Questo oggetto sarà ora memorizzato in un vettore nella classe ObjectManager e sarà disegnato quando il GameEngine chiama il metodo() in ogni fotogramma i drawObjects ObjectManager .
Potrei essere diventato un po 'paranoico ora dopo quell'articolo su Singletons (e potrebbe non aver avuto abbastanza tempo per girarmi intorno), ma sto iniziando a indovinare e mi chiedo se il modo in cui ho progettato il mio GameEngine era corretto (per mancanza di una parola migliore) e non cadeva nelle stesse insidie condivise dal pattern Singleton.
Qualsiasi commento sul mio post sarebbe molto apprezzato.
Modifica: Grazie per le risposte. Li apprezzo molto.Se possibile, mi piacerebbe se qualcuno potesse darmi qualche suggerimento riguardo ai due scenari di progetto pubblicati sopra. Come avrei potuto evitare l'uso di Singletons/Managers?
Con il primo, DI sarebbe stata la risposta corretta? Dovrei avere anche dato la vista di accesso al modello (questo è probabilmente più di una risposta MVC)? La vista trarrebbe vantaggio dall'implementazione di un'interfaccia (in modo da poter collegare più viste diverse)?
Nel secondo caso, in quale altro modo si sarebbe strutturata l'applicazione? La lamentela è semplicemente l'uso delle classi Manager rispetto a nomi più specifici? O è che, in alcuni casi, le classi possono essere ulteriormente suddivise (ad esempio ObjectHolder, ObjectDrawer, ObjectUpdater)?
+1 "Screw OOP" è una boccata d'aria fresca. Troppe persone identificano automaticamente e incondizionatamente "OOP" con "buono". Bjarne Stroustrup ha scritto su questo più di una volta. – fredoverflow
Non capisco perché "la cosa bella di questo approccio, rispetto a DI, è che rendi le tue dipendenze dolorosamente esplicite". Questo è quello che fai in DI; le tue classi specificano le loro dipendenze, sia in parametri costruttore, metodi setter o (yick) variabili private.Puoi farlo senza DI _framework_, ma ciò può essere complicato. Lo fa manualmente porta spesso alla classe A prendendo in classe B nel costruttore quando l'unico uso di B è quello di passarlo al costruttore della classe C. – NamshubWriter
@NamshubWriter: il mio punto è che con un framework DI, la classe registra le sue dipendenze , certo, e poi tipo di "apparire magicamente". Non è necessario passarli da dove sono stati creati dove sono necessari, in modo da non far "sentire" la dipendenza grap come si fa se l'unico modo per propagare le dipendenze è passandole come parametri. DI rende difficile vedere da dove viene una dipendenza * *. E non ti fornisce un modo chiaro per tracciare dove un certo oggetto è usato come dipendenza. Tutto dipende da una grande scatola nera di stato globale, che passa liberamente le dipendenze. – jalf