Es gibt keinen Kill wie Overkill
Zuallererst, lieber GiMmEtHaCoDeZ, versuchen wir, Ihre Aufgabe aufzuschlüsseln:
- Lesen Sie die Zahlen
- Sortieren Sie sie
- Ausgabe der sortierten Nummern.
Da "Teilen und Erobern" eine sehr wichtige Strategie bei der Arbeit mit Softwareproblemen ist, können Sie diese nacheinander angehen
1. Lesen
Ein weiteres wichtiges Thema in der Software ist die Vielseitigkeit. Da nicht festgelegt ist, wie der Benutzer die Zahlen eingibt, kann dies über die Konsole, über eine Datei, über einen Webdienst usw. geschehen. Daher ist es wichtig, dass unsere Lösung verschiedene Eingabetypen unterstützt. Der einfachste Weg, dies zu erreichen, besteht darin, den wichtigen Teil einer Schnittstelle zu extrahieren
public interface IDoubleArrayReader
{
IEnumerable<double> GetDoubles();
DoubleArrayReaderType Type {get;}
}
Wo DoubleArrayReaderType
ist eine Aufzählung gegeben mit
public enum DoubleArrayReaderType
{
Console,
File,
Database,
Internet,
Cloud,
MockService
}
Es ist auch wichtig, die Software von Grund auf testbar zu machen, damit eine Implementierung der Schnittstelle möglich ist
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;
}
}
}
Als nächstes ist die logische Frage, wie wir das entsprechende IDoubleArrayReader
in den Code laden können . Das ist einfach, solange wir eine einfache Fabrik benutzen:
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];
}
}
Beachten Sie, dass wir Reflection verwenden, um alle aktiven Reader zu laden, sodass zukünftige Erweiterungen automatisch verfügbar sind. Im Hauptteil unseres Codes tun wir Folgendes:
IDoubleArrayReader reader = DoubleArrayInputOutputFactory
.CreateDoubleArrayReader(DoubleArrayReaderType.MockService);
var doubles = reader.GetDoubles();
2. Bearbeitung (Sortierung)
Nun müssen wir die erhaltenen Zahlen verarbeiten, dh sortieren. Beachten Sie, dass die Schritte völlig unabhängig voneinander sind, sodass es für das Sortiersubsystem unerheblich ist, wie die Zahlen eingegeben wurden. Darüber hinaus kann sich das Sortierverhalten ändern, z. B. müssen wir möglicherweise einen effizienteren Sortieralgorithmus eingeben. Daher extrahieren wir natürlich das angeforderte Verarbeitungsverhalten in einer Schnittstelle:
public interface IDoubleArrayProcessor
{
IEnumerable<double> ProcessDoubles(IEnumerable<double> input);
DoubleArrayProcessorType Type {get;}
}
public enum DoubleArrayProcessorType
{
Sorter,
Doubler,
Tripler,
Quadrupler,
Squarer
}
Und das Sortierverhalten implementiert nur die Schnittstelle:
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;
}
}
}
Natürlich benötigen wir eine Factory, um die Verarbeitungsinstanzen zu laden und zu verwalten.
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. Schreiben Sie die Ausgabe
Hier gibt es nicht viel zu sagen, da dies ein Prozess ist, der die Eingabe widerspiegelt. Tatsächlich könnten wir die Lese- und Schreibfabriken in einer einzigen kombinieren DoubleArrayInputOutputFactory
:
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];
}
}
Alles zusammen
Schließlich wird unser Hauptprogramm nur all diese beeindruckenden Eigenschaften nutzen, die wir bereits erstellt haben. Der Code wird also einfach sein:
var doubles = reader.GetDoubles();
doubles = processor.ProcessDoubles(doubles);
writer.WriteDoublesArray(doubles);
wo, zum Beispiel könnten wir definieren reader
, writer
und processor
mit
IDoubleArrayReader reader = DoubleArrayInputOutputFactory.CreateDoubleArrayReader(DoubleArrayReaderType.MockService);
IDoubleArrayProcessor processor = DoubleArrayProcessorFactory.CreateDoubleArrayProcessor(DoubleArrayProcessorType.Sorter);
IDoubleArrayWriter writer = DoubleArrayInputOutputFactory.CreateDoubleArrayWriter(DoubleArrayWriterType.Console);