C # - Non c'è uccisione come eccessiva
Prima di tutto, caro GiMmEtHaCoDeZ, proviamo a scomporre il tuo compito:
- Leggi i numeri
- Ordinali
- Stampa i numeri ordinati.
Poiché "Dividi e conquista" è una strategia molto importante quando si lavora con problemi di software, è possibile affrontarli uno alla volta
1. Lettura
Un altro problema importante nel software è la versatilità. Dal momento che non è specificato come l'utente inserirà i numeri, ciò può accadere tramite la console, tramite un file, tramite un servizio web, ecc. Forse anche qualche metodo che non possiamo pensare al momento. Pertanto, è importante che la nostra soluzione sia in grado di supportare vari tipi di input. Il modo più semplice per raggiungere questo obiettivo è quello di estrarre la parte importante in un'interfaccia, diciamo
public interface IDoubleArrayReader
{
IEnumerable<double> GetDoubles();
DoubleArrayReaderType Type {get;}
}
dove DoubleArrayReaderType
viene data un'enumerazione
public enum DoubleArrayReaderType
{
Console,
File,
Database,
Internet,
Cloud,
MockService
}
È anche importante rendere il software testabile da zero, quindi sarà un'implementazione dell'interfaccia
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;
}
}
}
Successivamente, la domanda logica è come sapremo caricare l'appropriato IDoubleArrayReader
nel codice. È facile finché usiamo una semplice fabbrica:
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];
}
}
Si noti che, utilizziamo la riflessione per caricare tutti i lettori attivi, quindi eventuali estensioni future saranno automaticamente disponibili Ora, nel corpo principale del nostro codice di uscita, facciamo semplicemente:
IDoubleArrayReader reader = DoubleArrayInputOutputFactory
.CreateDoubleArrayReader(DoubleArrayReaderType.MockService);
var doubles = reader.GetDoubles();
2. Elaborazione (ordinamento)
Ora dobbiamo elaborare, cioè ordinare i numeri che abbiamo acquisito. Si noti che i passaggi sono completamente indipendenti l'uno dall'altro, quindi per il sottosistema di ordinamento, non importa come sono stati immessi i numeri. Inoltre, anche il comportamento dell'ordinamento è soggetto a modifiche, ad esempio potrebbe essere necessario introdurre un algoritmo di ordinamento più efficiente in atto. Quindi, naturalmente, estrarremo il comportamento di elaborazione richiesto in un'interfaccia:
public interface IDoubleArrayProcessor
{
IEnumerable<double> ProcessDoubles(IEnumerable<double> input);
DoubleArrayProcessorType Type {get;}
}
public enum DoubleArrayProcessorType
{
Sorter,
Doubler,
Tripler,
Quadrupler,
Squarer
}
E il comportamento dell'ordinamento implementerà semplicemente l'interfaccia:
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;
}
}
}
Naturalmente, avremo bisogno di una fabbrica per caricare e gestire le istanze di elaborazione.
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. Scrivere l'output
Non c'è molto da dire qui, poiché si tratta di un processo che rispecchia l'input. In effetti, potremmo combinare le fabbriche di lettura e scrittura in un singolo DoubleArrayInputOutputFactory
, in questo modo:
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];
}
}
Mettere tutto insieme
Infine, il nostro programma principale utilizzerà solo tutta questa meraviglia che abbiamo già creato, quindi il codice sarà:
var doubles = reader.GetDoubles();
doubles = processor.ProcessDoubles(doubles);
writer.WriteDoublesArray(doubles);
dove, ad esempio, potremmo definire reader
, writer
e processor
usando
IDoubleArrayReader reader = DoubleArrayInputOutputFactory.CreateDoubleArrayReader(DoubleArrayReaderType.MockService);
IDoubleArrayProcessor processor = DoubleArrayProcessorFactory.CreateDoubleArrayProcessor(DoubleArrayProcessorType.Sorter);
IDoubleArrayWriter writer = DoubleArrayInputOutputFactory.CreateDoubleArrayWriter(DoubleArrayWriterType.Console);