Design efficiente del codice per la ricerca di modelli usando un pattern Singleton

3

Ho difficoltà a trovare una progettazione di codice efficiente (thread-safe) per il seguente problema. Ci sono già da un po 'di tempo e apprezzerei davvero alcuni consigli e suggerimenti sul modo migliore per avvicinarsi a questo.

Sto fondamentalmente cercando vari pattern all'interno di un set di dati. Mi piacerebbe avere una classe "master". Io chiamo i modelli di questa classe. Sto pensando di fare di questa classe un modello singleton o una classe statica. Vorrei avere una sola istanza di questa master class. Sto codificando questa classe come un modello singleton (schema di Jon Skeet) in questo momento.

 public sealed class Patterns
 {
      private Patterns()
      {}

      public static Patterns Instance { get { return Nested.instance; } }

      private class Nested
      {
           // Explicit static constructor to tell C# compiler
           // not to mark type as beforefieldinit
           static Nested()
           {
                // ...  create a list to hold data for internal use
                List<Point> Data = new List<Point>();
           }

           internal static readonly Patterns instance = new Patterns();
      }
 }

Ho scelto uno schema singleton perché:

  1. Voglio che il singleton abbia classi annidate; una classe per ogni modello.
  2. Voglio che queste classi nidificate siano classi di istanze (cioè non statiche)
  3. Vorrei che il singleton istanziasse le classi nidificate, magari usando un pattern factory, se necessario.

Non sono sicuro che il mio ragionamento sia corretto, quindi qualsiasi consiglio sarebbe molto apprezzato.

Ora ho intenzione di aggiungere le varie classi di pattern come classi nidificate perché i pattern non hanno senso al di fuori della classe Master pattern. Inoltre, IPattern è un'interfaccia per i pattern.

 public sealed class Patterns
 {
      private Patterns()
      {}

      public static Patterns Instance { get { return Nested.instance; } }

      private class Nested
      {
           // Explicit static constructor to tell C# compiler
           // not to mark type as beforefieldinit
           static Nested()
           {
                // ...  create a list to hold data for internal use
                static List<Point> Data = new List<Point>();

                // ... indices to track occurences of each pattern
                static int AIndex = 0;
                static int BIndex = 0;
                static int CIndex = 0;
           }

           internal static readonly Patterns instance = new Patterns();
      }

      // ... Methods

      public bool SearchForPattern(Point dataPoint)
      {
           // ... add data to list
           Data.Add(dataPoint);
      }

      // ... nested pattern classes

      class PatternA : IPattern
      {
           static int = some integer
           static double[] arr = new double[];

           // ... do some work
      }

      class PatternB : IPattern
      {
           // ... do some work
      }

      class PatternC : IPattern
      {
           // ... do some work
      }
 }

I dati dell'elenco sono statici perché voglio che i dati vengano conservati per tutta la durata dell'applicazione. Lo stesso vale per i campi statici nelle classi annidate.

Questo è il punto in cui ora comincio a perdersi davvero. Nel metodo SearchForPattern (Point dataPoint) vorrei fare quanto segue:

      public bool SearchForPattern(Point dataPoint)
      {
           // ... add data to list
           Data.Add(dataPoint);

           bool haveA = PatternA.SearchForA();
           if (haveA)
           {
                PatternA a1 = new PatternA();     // the number after a will change as other A patterns are found; as per AIndex value
                AIndex++;
           }

                ... and so on for other patterns
      }

Quindi ecco le mie domande. Nota che sono abbastanza nuovo in C # e sto cercando di imparare.

  1. È questo l'approccio migliore (ossia la più efficiente dal punto di vista del calcolo) da adottare con questo problema? In caso contrario, puoi suggerire un approccio alternativo?

  2. Non so come incorporare il modello factory per l'istanziazione delle classi pattern nidificate. Questo dovrebbe essere fatto? Se sì, puoi suggerire come?

  3. Mi manca qualcosa qui che devo prendere in considerazione ma che non ho considerato finora?

posta Zeos 12.10.2014 - 21:29
fonte

1 risposta

5

I have chosen a singleton pattern because:

  1. I want the singleton to hold nested classes; one class for each pattern.

Questo non richiede un singleton o una classe statica. Potresti avere

public class Patterns // non-static
{
    public class PatternA : IPattern { }
    public class PatternB : IPattern { }
}

e potresti utilizzarlo come contenitore per le tue definizioni di pattern e istanziare istanze di PatternA e PatternB uguali.

  1. I want these nested classes to be instance classes (i.e. not static)

Questo di nuovo non ha nulla a che fare con l'uso di un singleton (vedi sopra).

  1. I would like the singleton to instantiate the nested classes, perhaps using a factory pattern, as needed.

Ancora una volta, non è necessario alcun singleton. Potresti avere una fabbrica di modelli non statici:

public class PatternsFactory
{
    public IEnumerable<IPattern> CreatePatterns()
    {
        return new List<IPattern> 
        {
            new Patterns.PatternA(), 
            new Patterns.PatternB()
        };
    }
}

Now I plan to add the various pattern classes as nested classes because patterns do not make sense outside the master Pattern class.

E perché no? Ecco a cosa servono gli spazi dei nomi . Usare una classe ombrello come una borsa per le definizioni di classe sembra reinventare la ruota per me. I namespace servono proprio a questo scopo: raggruppare classi correlate. Perché rimbalzarli dal loro unico lavoro?

Se i pattern non hanno senso al di fuori dello spazio dei nomi Patterns , contrassegnali come internal , che è invisibile al di fuori dello spazio dei nomi. Potresti voler mantenere IPattern di per sé pubblico a scopo di test, anche se (di questo in un attimo).

Am I missing anything here that I need to consider but have not considered so far?

Uno dei motivi per cui l'uso della statistica è disapprovato è testabilità . Come scriveresti una suite di test unitari per la tua funzionalità di abbinamento dei pattern? Non puoi creare un modello fittizio, perché non puoi inserire un altro motivo nella tua classe Pattern . Diamine, non puoi nemmeno creare una sottoclasse, dato che hai reso sealed .

Stai forzando tutti i pattern a salvare le loro corrispondenze in un oggetto Data statico, il che significa che il test richiede di pulirlo dopo ogni test. E ancora, non c'è modo di ignorarlo, oltre a riscrivere la cosa.

Altre letture sull'argomento:

Un'altra preoccupazione è estensibilità . Cosa succede ogni volta che vuoi aggiungere un altro pattern? Devi modificare la tua classe Patterns e inserire un'altra implementazione. Devi modificare il codice di SearchForPattern per aggiungere tutte queste belle

if (haveN) PatternN n = new PatternN();

Questo è inflessibile e difficile da mantenere. Il principio aperto / chiuso afferma che il codice deve essere aperto per l'estensione e il tuo approccio lo esclude.

If not, can you please suggest an alternative approach?

Vorrei abbandonare i singleton, perché non vedo alcuno scopo di usarli. Creerei un PatternFactory , in grado di restituire un set di tutti gli oggetti IPattern supportati e creare un'istituzione della fabbrica ovunque ne avessi bisogno (è comunque stateless).

Per quanto riguarda le corrispondenze data - pattern che si desidera mantenere per tutta la durata dell'applicazione ( List Data is static because I want the data to be retained throughout the lifetime of the application ), beh, è possibile renderlo statico, sebbene non sia l'unico modo possibile per legare il suo ciclo di vita a quello dell'applicazione.

Ma perché essere grato di metterlo nello stesso oggetto di classe in cui sono definiti tutti i pattern ?? Conoscere tutti i pattern supportati e persistere di tutte le corrispondenze di pattern che abbiamo rilevato da qualche parte non sono la stessa responsabilità (vedi Principio di singola responsabilità ). Questa scelta di design odora di God object antipattern .

Is this the best (i.e. most computationally efficient) approach to take with this problem?

Ciò che è computazionalmente costoso qui è il modello corrispondente a se stesso, per quantità non banali di dati almeno. Pertanto, il costo della creazione di istanze rispetto all'utilizzo di una classe statica è trascurabile, quindi per quanto riguarda il design OOP, non mi aspetto che le prestazioni siano influenzate.

    
risposta data 12.10.2014 - 23:39
fonte

Leggi altre domande sui tag