Variabili di stato globali e passaggio parametri del costruttore

0

Verranno utilizzate un paio di variabili di sola lettura. Quasi tutte le classi useranno queste variabili. O metto tutte le variabili in una classe statica interna separata o le passo più volte in tutti i parametri del costruttore delle classi. Quale sarebbe la migliore del 2? Per quanto riguarda le prestazioni, per favore.

    
posta Gwapo 22.05.2018 - 19:23
fonte

3 risposte

0

Either I place all of the variables in a separate internal static class or I pass them on repeatedly in all the classes' constructor parameters.  What would be the better of the 2? Performance-wise only please.

Come hanno notato i commentatori, ci sarà una differenza per lo più trascurabile dal punto di vista delle prestazioni di velocità.

L'unico modo per trovare una differenza significativa è se hai set di dati (conteggi di oggetti di istanza) che sono estremamente grandi - in quanto potresti notare una differenza di utilizzo dello spazio, che a una scala estrema si tradurrà in una velocità differenza pure.

Tuttavia, questo presuppone alcuni dettagli che deduco dalla tua domanda, e queste ipotesi potrebbero non valere ..

Quello che sto ottenendo è che l'approccio della "classe statica con membri statici" utilizza l'accoppiamento stretto del codice in alcune classi con i dati statici nell'altra classe. Ovviamente, questo approccio non consentirà a istanze diverse di avere contesti diversi, ma quindi non stiamo prendendo meriti di manutenzione e / o usabilità, solo prestazioni. Di conseguenza, ciò farà risparmiare su alcuni dati di istanza rispetto ad altri approcci.

Nell'approccio "passate su ripetutamente ... classi di parametri di costruzione", sto assumendo che i costruttori memorizzino / inoltrino questi parametri formali in variabili d'istanza nelle rispettive classi - e queste istanze rappresentino quindi istanze più grandi di avremmo un approccio più strettamente accoppiato.

Tuttavia, invece di fornire più parametri più e più volte, potremmo fornire un singolo oggetto di contesto (condivisibile) contenente più valori come parametro del costruttore da memorizzare nelle istanze. Sebbene questo rappresenti un minor numero di parametri da passare e quindi archiviare, ora è un riferimento, ovvero 64 bit su un'architettura a 64 bit (dove due o più booleani a 32 bit non sarebbero stati più grandi). Quindi, questo è uno spazio vincente solo se il numero e la dimensione dei parametri è maggiore della dimensione del puntatore.

Se d'altra parte, i costruttori calcolano con questi parametri e non li memorizzano nell'istanza per l'uso dell'istanza dell'oggetto (metodi da usare), allora non c'è penalità di spazio, e quindi siamo tornati a trascurabili differenze di rendimento.

In breve, se c'è un costo di spazio per un approccio rispetto ad un altro, può essere visualizzato quando ci sono volumi molto elevati di istanze e, di solito, più spazio viene utilizzato, più lento è il codice a causa di problemi di efficienza della cache ( a parità di altre condizioni, come l'algoritmo generale).

    
risposta data 24.05.2018 - 02:22
fonte
11

Performance-wise only please.

Hai già preso la decisione sbagliata, proprio lì. Questo è chiamato "ottimizzazione prematura" ed è disapprovato, per buone ragioni.

La domanda corretta da porre è quale effetto avranno i due approcci sulla facilità di lettura, test, ragionamento e mantenimento del codice. E la risposta a questo si riduce a quanto immutabili siano queste "variabili". Come sono impostati? Cosa intendi per loro sono di sola lettura? Sono completamente immutabili o semplicemente di sola lettura da una prospettiva esterna, ma possono cambiare internamente?

Si tratta di trade-off. Avere valori globali immutabili può migliorare la leggibilità del tuo codice e ridurre la quantità di parametri che devi passare. Ma aumenta l'accoppiamento e può rendere più difficili i test. E se possono cambiare in qualsiasi modo, allora sono un enorme anti-pattern variabile globale malvagio e dovresti scappare urlando persino se li consideri.

    
risposta data 22.05.2018 - 19:52
fonte
3

Fai entrambe le cose, usando IoC

Dovresti fare entrambi , utilizzando un Inversion of Control container, che insieme al LSP fornirà una netta separazione delle preoccupazioni e faciliterà notevolmente i test delle unità automatizzate.

L'idea è di definire una classe "statica" (non propriamente) e di iniettarla nel costruttore ovunque sia necessaria. Il contenitore si occupa dell'istanzia per te, e puoi impostare le tue impostazioni come "singleton" o "single instance", che essenzialmente lo rendono come una classe statica, solo tu puoi stub e simulare la sua interfaccia. Non saresti in grado di farlo con una normale classe statica.

In questo esempio userò un contenitore IoC comune noto come Autofac (che è gratuito e disponibile su NuGet. Ce ne sono anche molti altri.) Per prima cosa definiamo un'interfaccia che espone le impostazioni di cui abbiamo bisogno:

public interface ISettings
{
    string Setting1 { get; }
    string Setting2 { get; }
}

Quindi definiamo un'implementazione concreta.

public class GlobalSettings : ISettings
{
    //These are just examples. In production code, perhaps they are database calls.
    public string Setting1 { get { return "Foo"; } }
    public string Setting2 { get { return "Bar"; } }
}

Quindi aggiungiamo le nostre impostazioni a composizione root , insieme alla nostra applicazione:

public static IContainer CompositionRoot()
{
    var builder = new ContainerBuilder();
    builder.RegisterType<GlobalSettings>().As<ISettings>().SingleInstance();
    builder.RegisterType<Application>();
    return builder.Build();
}

Oh, a proposito, ecco l'applicazione. Questo è solo un esempio fittizio:

public class Application
{
    private readonly ISettings _settings;

    public Application(ISettings settings)  //Injected automatically
    {
        _settings = settings;
    }

    public void Run()
    {
        Console.WriteLine("Setting1 = '{0}'", _settings.Setting1);
        Console.WriteLine("Setting2 = '{0}'", _settings.Setting2);
    }
}

Ora per eseguirlo, chiamiamo la composizione root per comporre il grafo dell'oggetto, chiediamo ad Autofac di darci un'applicazione e chiama Run() . Il contenitore inietterà automaticamente le impostazioni e inietterà sempre la stessa istanza. È molto facile. Finisce per essere una riga di codice:

public static void Main()
{
    CompositionRoot().Resolve<Application>().Run();
}

Ed ecco l'output da Applicazione:

Setting1 = 'Foo'
Setting2 = 'Bar'

Ecco un esempio operativo completo su DotNetFiddle .

Quanto sopra è uno schema molto comune e consiglio vivamente di impararlo. Inoltre, soddisferà sicuramente le tue tendenze OCD, poiché mantiene tutto molto organizzato.

Prestazioni

I mezzi con cui si forniscono le variabili dove sono necessari non sono suscettibili di spostare l'ago rispetto alle prestazioni. Tuttavia, strutturare il codice in questo modo farà due cose per aiutarti con le prestazioni:

  1. Avendo un codice ben strutturato che è più semplice da mantenere, il tuo team di sviluppo avrà più tempo per concentrarsi su argomenti relativi alle prestazioni.

  2. La possibilità di sostituire mock e stub significa che è possibile isolare parti di codice e testarle in modo indipendente, il che può aiutare a determinare da dove provengono i problemi di prestazioni. Ad esempio, se si isola il client del database e le cose si accelerano, è probabile che l'accesso ai dati sia il collo di bottiglia.

Ad esempio, diciamo che scopriamo che la nostra applicazione sta funzionando molto lentamente e sospettiamo che la logica di recupero dei dati nella nostra classe GlobalSettings stia causando il problema. Possiamo facilmente creare un mockup:

public class MockSettings : ISettings
{
    //Dummy implementation without database calls
}

e registralo invece di GlobalSettings:

builder.RegisterType<MockSettings>().As<ISettings>().SingleInstance();

E ora quando eseguiamo l'applicazione, le chiamate al database non avvengono e possiamo dire quale parte del problema delle prestazioni è isolata e cosa rimane.

    
risposta data 22.05.2018 - 21:13
fonte

Leggi altre domande sui tag