Decisione progettuale per memorizzare istanze / riferimenti già costruiti

5

Sto lavorando all'applicazione WPF e ho bisogno di una migliore decisione di progettazione per uno scenario. Fondamentalmente, sto leggendo un assembly .net per estrarre i tipi e le proprietà e mapparlo alle mie classi personalizzate create per contenere quei dati per renderlo serializzabile. Durante l'estrazione, ho richiesto un modo per non leggere di nuovo lo stesso tipo se viene rilevato come parte di alcuni tipi di proprietà.

problema

Voglio un modo per ricordare tutti i tipi estratti e quando appaiono di nuovo usano lo stesso riferimento da qualche memoria in-memory.

Ora posso pensare a una soluzione che utilizzi il modello di progettazione Cache o Factory. Ma ha bisogno di un verdetto esperto per fare colpo su questa situazione.

Attualmente, ho progettato sotto la classe per conservare e memorizzare i riferimenti.

public abstract class Factory<S, T> : IFactory<S, T>
{
    private static readonly Dictionary<S, T> Cache = new Dictionary<S, T>();

    public T Create(S source)
    {
        if (!Cache.ContainsKey(source))
        {
            Cache.Add(source, CreateInstance(source));
        }
        return Cache[source];
    }

    protected abstract T CreateInstance(S source);
}
    
posta Furqan Safdar 17.12.2016 - 14:53
fonte

1 risposta

1

Escludendo i discendenti di Factory factory nella stessa memoria (rendendo il valore di ritorno indeterminato), il tuo approccio funzionerebbe bene per applicazioni a thread singolo non coperte con i test Unit e implementando un'architettura monolith.

Suggerisco:

  • evitare di utilizzare lo stato globale (Singleton o membro statico)
  • inserire l'interfaccia di fabbrica nei client per poter sostituire l'implementazione (in particolare, renderebbe più facile disabilitare la memoizzazione e testare i client)
  • introduce la sicurezza dei thread
  • separa i problemi di memorizzazione nella cache e creazione
  • cover cache e factory con test Unit separati
  • test delle prestazioni con e senza memoization

Ad esempio:

using System;
using System.Diagnostics;
using System.Collections.Concurrent;

/// Generic factory interface. Consider using Func<S,T> instead
public interface IFactory<S, T> {
  T Create(S source);
}

/// Memoization decorator
public sealed class MemoizedFactory<S, T> : IFactory<S, T> {
    private readonly IFactory<S, T> toDecorate;
    // Accessed from different threads
    private readonly ConcurrentDictionary<S, T> cache = new ConcurrentDictionary<S, T>();
    public MemoizedFactory(IFactory<S, T> toDecorate) {
       this.toDecorate = toDecorate;
    }
    public T Create(S source) {
       return cache.GetOrAdd(source, toDecorate.Create);
    }
}

public sealed class PrefixFactory: IFactory<String, String>  {
       public int invocationCount = 0;
       public String Create(String source) {
           invocationCount++;
           return "prefix" + source;
       }
}

class TestClass
    {
        static void Main(string[] args)
        {
            var prefixFactory = new PrefixFactory();
            var memoizedFactory = new MemoizedFactory<String, String>(prefixFactory);
            Trace.Assert(memoizedFactory.Create("test") == "prefixtest");
            Trace.Assert(prefixFactory.invocationCount == 1);
            Trace.Assert(memoizedFactory.Create("test") == "prefixtest");
            Trace.Assert(prefixFactory.invocationCount == 1);
            Trace.Assert(memoizedFactory.Create("test2") == "prefixtest2");
            Trace.Assert(prefixFactory.invocationCount == 2);
        }
    }
    
risposta data 19.12.2016 - 18:06
fonte

Leggi altre domande sui tag