C # - Il n'y a pas de mort comparable à l'overkill
Tout d’abord, cher GiMmEtHaCoDeZ, essayons de décomposer votre tâche:
- Lire les chiffres
- Les trier
- Sortez les nombres triés.
Comme "Diviser et conquérir" est une stratégie très importante lorsque vous travaillez avec des problèmes logiciels, abordons-les un à la fois.
1. lecture
Un autre problème important dans le logiciel est la polyvalence. Comme il n’est pas spécifié comment l’utilisateur entrera les chiffres, cela peut se faire via la console, via un fichier, via un service Web, etc. Peut-être même une méthode à laquelle nous ne pouvons pas penser pour le moment. Il est donc important que notre solution puisse prendre en charge différents types de saisie. Le moyen le plus simple d'y parvenir consiste à extraire la partie importante d'une interface, disons
public interface IDoubleArrayReader
{
IEnumerable<double> GetDoubles();
DoubleArrayReaderType Type {get;}
}
où DoubleArrayReaderType
est une énumération donnée avec
public enum DoubleArrayReaderType
{
Console,
File,
Database,
Internet,
Cloud,
MockService
}
Il est également important de rendre le logiciel testable à partir de la base, de sorte qu'une implémentation de l'interface sera
public class MockServiceDoubleArrayReader : IDoubleArrayReader
{
IEnumerable<double> IDoubleArrayReader.GetDoubles()
{
Random r = new Random();
for(int i =0; i<=10; i++)
{
yield return r.NextDouble();
}
}
DoubleArrayReaderType IDoubleArrayReader.Type
{
get
{
return DoubleArrayReaderType.MockService;
}
}
}
Ensuite, la question logique est de savoir comment nous saurons charger IDoubleArrayReader
le code approprié . C'est facile tant que nous utilisons une usine simple:
public static class DoubleArrayInputOutputFactory
{
private static Dictionary<DoubleArrayReaderType, IDoubleArrayReader> readers;
static DoubleArrayInputOutputFactory()
{
readers = new Dictionary<DoubleArrayReaderType, IDoubleArrayReader>();
foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())
{
try
{
var instance = Activator.CreateInstance(type);
if (instance is IDoubleArrayReader)
{
readers.Add((instance as IDoubleArrayReader).Type,
(instance as IDoubleArrayReader));
}
}
catch
{
continue;
}
}
}
public static IDoubleArrayReader CreateDoubleArrayReader(DoubleArrayReaderType type)
{
return readers[type];
}
}
Notez que, comme nous utilisons la réflexion pour charger tous les lecteurs actifs, toutes les extensions futures seront automatiquement disponibles. Maintenant, dans le corps principal du code externe, nous ne faisons que:
IDoubleArrayReader reader = DoubleArrayInputOutputFactory
.CreateDoubleArrayReader(DoubleArrayReaderType.MockService);
var doubles = reader.GetDoubles();
2. Traitement (tri)
Nous devons maintenant traiter, c'est-à-dire trier les nombres que nous avons acquis. Notez que les étapes sont complètement indépendantes les unes des autres, donc, pour le sous-système de tri, la façon dont les nombres ont été entrés n'a pas d'importance. De plus, le comportement de tri est également sujet à modification, par exemple, nous pourrions avoir besoin de mettre en place un algorithme de tri plus efficace. Alors, naturellement, nous allons extraire le comportement de traitement demandé dans une interface:
public interface IDoubleArrayProcessor
{
IEnumerable<double> ProcessDoubles(IEnumerable<double> input);
DoubleArrayProcessorType Type {get;}
}
public enum DoubleArrayProcessorType
{
Sorter,
Doubler,
Tripler,
Quadrupler,
Squarer
}
Et le comportement de tri implémentera simplement l'interface:
public class SorterDoubleArrayProcessor : IDoubleArrayProcessor
{
IEnumerable<double> IDoubleArrayProcessor.ProcessDoubles(IEnumerable<double> input)
{
var output = input.ToArray();
Array.Sort(output);
return output;
}
DoubleArrayProcessorType IDoubleArrayProcessor.Type
{
get
{
return DoubleArrayProcessorType.Sorter;
}
}
}
Bien entendu, nous aurons besoin d’une usine pour charger et gérer les instances de traitement.
public static class DoubleArrayProcessorFactory
{
private static Dictionary<DoubleArrayProcessorType, IDoubleArrayProcessor> processors;
static DoubleArrayProcessorFactory()
{
processors = new Dictionary<DoubleArrayProcessorType, IDoubleArrayProcessor>();
foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())
{
try
{
var instance = Activator.CreateInstance(type);
if (instance is IDoubleArrayProcessor)
{
processors.Add((instance as IDoubleArrayProcessor).Type, (instance as IDoubleArrayProcessor));
}
}
catch
{
continue;
}
}
}
public static IDoubleArrayProcessor CreateDoubleArrayProcessor(DoubleArrayProcessorType type)
{
return processors[type];
}
}
3. Écrire la sortie
Il n’ya pas grand chose à dire ici, car c’est un processus qui reflète l’entrée. En fait, nous pourrions combiner les usines de lecture et d’écriture en une seule DoubleArrayInputOutputFactory
, comme ceci:
public interface IDoubleArrayWriter
{
void WriteDoublesArray(IEnumerable<double> doubles);
DoubleArrayWriterType Type {get;}
}
public enum DoubleArrayWriterType
{
Console,
File,
Internet,
Cloud,
MockService,
Database
}
public class ConsoleDoubleArrayWriter : IDoubleArrayWriter
{
void IDoubleArrayWriter.WriteDoublesArray(IEnumerable<double> doubles)
{
foreach(double @double in doubles)
{
Console.WriteLine(@double);
}
}
DoubleArrayWriterType IDoubleArrayWriter.Type
{
get
{
return DoubleArrayWriterType.Console;
}
}
}
public static class DoubleArrayInputOutputFactory
{
private static Dictionary<DoubleArrayReaderType, IDoubleArrayReader> readers;
private static Dictionary<DoubleArrayWriterType, IDoubleArrayWriter> writers;
static DoubleArrayInputOutputFactory()
{
readers = new Dictionary<DoubleArrayReaderType, IDoubleArrayReader>();
writers = new Dictionary<DoubleArrayWriterType, IDoubleArrayWriter>();
foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())
{
try
{
var instance = Activator.CreateInstance(type);
if (instance is IDoubleArrayReader)
{
readers.Add((instance as IDoubleArrayReader).Type, (instance as IDoubleArrayReader));
}
}
catch
{
continue;
}
}
foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())
{
try
{
var instance = Activator.CreateInstance(type);
if (instance is IDoubleArrayWriter)
{
writers.Add((instance as IDoubleArrayWriter).Type, (instance as IDoubleArrayWriter));
}
}
catch
{
continue;
}
}
}
public static IDoubleArrayReader CreateDoubleArrayReader(DoubleArrayReaderType type)
{
return readers[type];
}
public static IDoubleArrayWriter CreateDoubleArrayWriter(DoubleArrayWriterType type)
{
return writers[type];
}
}
Mettre tous ensemble
Enfin, notre programme principal utilisera simplement toute cette génialité que nous avons déjà construite. Le code sera donc simplement:
var doubles = reader.GetDoubles();
doubles = processor.ProcessDoubles(doubles);
writer.WriteDoublesArray(doubles);
où, par exemple, nous pourrions définir reader
, writer
et en processor
utilisant
IDoubleArrayReader reader = DoubleArrayInputOutputFactory.CreateDoubleArrayReader(DoubleArrayReaderType.MockService);
IDoubleArrayProcessor processor = DoubleArrayProcessorFactory.CreateDoubleArrayProcessor(DoubleArrayProcessorType.Sorter);
IDoubleArrayWriter writer = DoubleArrayInputOutputFactory.CreateDoubleArrayWriter(DoubleArrayWriterType.Console);