Un modo migliore di fornire accesso a una singola classe "back-end" all'intera applicazione

1

La mia applicazione sta diventando sempre più complessa.

Attualmente, ho una collezione di classi che compongono un "Backend", questo contiene un DataInterface che parla con un database e restituisce le classi POCO, un ModelProvider che li avvolge nei modelli e un ViewModelProvider che crea viste, tutto dipendenti l'uno dall'altro.

Queste istanze vengono create all'avvio dell'applicazione e quindi racchiuse in una singola classe "back-end". C'è solo un'istanza di questo per l'applicazione. Sto scoprendo che molte, molte classi hanno bisogno di portare in giro questa istanza di Backend per funzionare.

Ho anche un AppController di classe che controlla la navigazione di alto livello e cose come mostrare dialoghi.

Di conseguenza, queste due classi vengono passate nei costruttori per quasi tutti i ViewModel che faranno qualsiasi cosa che sia stata completata.

Questo non mi sembra sensato, ma deve essere un problema molto comune avere un paio di classi a istanza singola a cui è necessario accedere in tutta l'applicazione.

Stavo pensando che una soluzione sarebbe quella di creare una singola classe statica (ad esempio la classe "backend" già esistente) che potrebbe tenere traccia di ciò, quindi tutto ciò che devo fare è:

StaticBackend.ViewModelProvider.GetSomeViewModelsForMe();

Questa è una buona pratica o esiste un modo più consolidato per farlo?

Iniezione di dipendenza:

Sto cercando di capire come si fa l'iniezione di dipendenza. Sembra che non sia lontano se inizio a creare interfacce per ModelProvider, ViewModelProvider ecc.

Sembra che mi troverei in un posto simile, tranne che le cose potrebbero essere formalmente più sensate, dovrei comunque "iniettare" le classi di IModelProvider e IViewModelProvider fino in fondo dal costruttore al costruttore.

Ecco come stanno le cose al momento (ma incapsulando parte del back-end in interfacce):

interface INavagationManager
{
    void NavagateTo(Page page);
}

interface IViewModelProvider
{
    void CreateSomeViewModelsToDisplay();
}

class HomePage : Page
{
    INavagationManager NavagationManager;
    IViewModelProvider ViewModelProvider;

    //this contains no dependencies on the IViewModelProvider, but it does with INavagationManager
    public HomePage(INavagationManager navagationManager, IViewModelProvider viewModelProvider) {
        this.NavagationManager = navagationManager;
        //this is "injected" but it's not really a dependency of HomePage, as it never wants to get ViewModels, but the pages it creates do
        this.ViewModelProvider = viewModelProvider;
    }

    public void UserWantsToNavagateSomewhere()
    {
        //all ViewModelProvider exists for is to be passed on down the 'chain'
        NavagationManager.NavagateTo(new SubPage(ViewModelProvider));
    }
}

class SubPage : Page
{
    IViewModelProvider ViewModelProvider;
    List<MyViewModel> MyViewModels;

    public SubPage(IViewModelProvider viewModelProvider)
    {
        ViewModelProvider = viewModelProvider;

        //actually use this dependency for something
        MyViewModels = ViewModelProvider.CreateSomeViewModelsToDisplay();
    }
}

L'uso delle interfacce facilita l'esecuzione di UnitTesting in futuro, in quanto è possibile alimentarlo in INavagationManager ecc. per testare il comportamento. Ma sono ancora nella stessa posizione in cui ero prima, sono ancora un po 'confuso su come i contenitori IoC si adattano.

Sembra che creerei un container, che si occupa delle dipendenze di iniezione come IViewModelProvider e INavagationManager nell'esempio sopra, e preferirei passare il contenitore tra tutti gli oggetti? In questo modo:

interface INavagationManager
{
    void NavagateTo(Page page);
}

interface IViewModelProvider
{
    void CreateSomeViewModelsToDisplay();
}

class HomePage : Page
{
    Container Container;
    INavagationManager NavagationManager;

    //this contains no IViewModelProvider, but in instance of Container
    public HomePage(Container container, IViewModelProvider viewModelProvider) {
        this.NavagationManager = navagationManager;
        this.Container= container;
    }

    public void UserWantsToNavagateSomewhere()
    {
        //all ViewModelProvider exists for is to be passed on down the 'chain'
        NavagationManager.NavagateTo(Container.GetInstance<SubPage>());
    }
}

class SubPage : Page
{
    IViewModelProvider ViewModelProvider;
    List<MyViewModel> MyViewModels;

    public SubPage(IViewModelProvider viewModelProvider)
    {
        ViewModelProvider = viewModelProvider;

        //actually use this dependency for something
        MyViewModels = ViewModelProvider.CreateSomeViewModelsToDisplay();
    }
}
    
posta Joe 12.05.2016 - 13:12
fonte

2 risposte

3

Quel singleton sarà un mal di testa da gestire, in particolare per quanto riguarda testing .

Ciò che vuoi veramente è iniettare questa dipendenza nei tuoi componenti (come indicato sopra - questa è chiamata Iniezione di dipendenza o inversione di controllo, nota anche come IoC). È possibile gestire quali componenti lo ricevono e sostituirlo nel proprio ambiente di test. Se non lo fai, allora i tuoi componenti creeranno un'istanza per quello vero e potrebbero non volerlo durante un ciclo di test (molto meglio in molti casi fornire una simulazione contenente dati di esempio, ecc.)

Hai notato che dovrai iniettarlo in molti posti. Potrebbe essere il caso, se si tratta di una dipendenza chiave per i tuoi componenti. Non necessariamente indica un problema in sé. Potresti riuscire a semplificarti la vita investigando su alcuni contenitori IoC, ad es. Unity

    
risposta data 12.05.2016 - 14:19
fonte
-1

Quello che stai descrivendo sembra un Singleton?

link

L'idea con Singleton Pattern è che hai solo un'istanza di un oggetto. Esempio di seguito riportato, commentato in pseudo-codice Java:

public final class Singleton {
    // Here the singleton is created (at program start up, right before execution)
    private static final Singleton instance = new Singleton();

    private Singleton() { you fill your constructor code here } // notice that the constructor is private, and can only be used inside this class.

    public static Singleton GetInstance() {
        return instance; // this returns a reference to the singleton
    }
    .. else you just add functions her as you normally would do ..

}

l'utilizzo è Singleton.GetInstance (). TheFunctionYouWouldLikeToCall ()

Nel tuo caso, sostituisci "Singleton" in alto con "StaticBackend" se lo desideri.

(Nel tuo caso, e probabilmente molti altri) penso che sia una pratica migliore che lasciare che gli stessi pochi oggetti vengano passati con metodi quasi ovunque accessibili.

Argomenti contro singleton:

link

che si riferisce a questo: link

    
risposta data 12.05.2016 - 13:30
fonte

Leggi altre domande sui tag